Ios 如何将目标动作转换为块?
我在一个类中有以下选择器:Ios 如何将目标动作转换为块?,ios,objective-c,objective-c-blocks,Ios,Objective C,Objective C Blocks,我在一个类中有以下选择器: - (SoapRequest*) loginAndConnect: (id) target action: (SEL) action credentials: (WSAcredentials*) arg0 dialoutInfo: (WSAdialoutInfo*) arg1; 我希望能够使用一个块而不是另一个选择器来调用它作为操作,但我找不到有关如何执行此操作的信息。比如: [service loginAndConnect:self credential
- (SoapRequest*) loginAndConnect: (id) target action: (SEL) action credentials: (WSAcredentials*) arg0 dialoutInfo: (WSAdialoutInfo*) arg1;
我希望能够使用一个块而不是另一个选择器来调用它作为操作,但我找不到有关如何执行此操作的信息。比如:
[service loginAndConnect:self credentials:credentials dialoutInfo:dialoutInfo action:^(SoapRequest* aResult) {
// more code here
}];
实现这一目标的最佳方式是什么
更新**
我几乎可以做到这一点,但在objc_发布版中,completionBlock对象出现了一个异常。我确信这与保留目标有关,但我不确定如何纠正它。以下是当前代码:
- (BOOL) checkService {
WSAcredentials* credentials = [[WSAcredentials alloc] init];
WSAdialoutInfo* dialoutInfo = [[WSAdialoutInfo alloc] init];
if (!service) {
service = [[WSAWebSocketAdapterService alloc] init];
}
__block SoapRequest* request;
[service loginAndConnectWithCredentials:credentials dialoutInfo:dialoutInfo completionBlock:^(SoapRequestCompletionBlock completionBlock) {
request = (SoapRequest*)completionBlock;
if ([request isKindOfClass: [SoapFault class]]) {
return YES; // we got a response, that's all we care about
}
return NO;
}
];
return YES;
}
这是我的分类,非常接近下面发布的内容:
#import "WSAWebSocketAdapterService+BlockExtension.h"
// These objects serve as targets (with action being completed:) for the original object.
// Because we use one for each request we are thread safe.
@interface MyCustomSoapTargetAction : NSObject
@property (copy) SoapRequestCompletionBlock block;
- (void) completed:(id)sender;
@end
@implementation MyCustomSoapTargetAction
- (void) completed:(id)sender
{
// Assuming 'sender' is your SoapRequest
if (_block != nil)
_block(sender);
_block = nil;
}
@end
@implementation WSAWebSocketAdapterService(BlockExtension)
- (SoapRequest*) loginAndConnectWithCredentials:(WSAcredentials*) arg0
dialoutInfo: (WSAdialoutInfo*) arg1
completionBlock:(BOOL (^)(SoapRequestCompletionBlock))completionBlock
{
MyCustomSoapTargetAction *target = [[MyCustomSoapTargetAction alloc] init];
target.block = (SoapRequestCompletionBlock) completionBlock;
//
// Here we assume that target will be retained.
// If that's not the case then we will need to add it to some collection before
// the call below and have the target object remove itself from it after its
// block has been called.
//
return [self loginAndConnect:target action:@selector(completed:) credentials:arg0 dialoutInfo:arg1];
}
@end
谢谢你的帮助 您有权访问该类的源代码吗?生成一个接受块而不是选择器的类似方法将是一个相当简单的重写 AFNetworking库是这类东西的一个很好的风格指南。您的方法可能与此类似:
+ (instancetype)JSONRequestOperationWithRequest:(NSURLRequest *)urlRequest
success:(void (^)(NSURLRequest *request, NSHTTPURLResponse *response, id JSON))success
failure:(void (^)(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error, id JSON))failure;
或者,您可以使用此处演示的方法通过一个类别添加您的方法:您有权访问该类的源吗?生成一个接受块而不是选择器的类似方法将是一个相当简单的重写 AFNetworking库是这类东西的一个很好的风格指南。您的方法可能与此类似:
+ (instancetype)JSONRequestOperationWithRequest:(NSURLRequest *)urlRequest
success:(void (^)(NSURLRequest *request, NSHTTPURLResponse *response, id JSON))success
failure:(void (^)(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error, id JSON))failure;
或者,您可以使用此处演示的方法,通过一个类别添加您的方法:您实际上不需要源代码。一个类别就可以了。下面是一些示例代码,让您开始学习, 这甚至是线程安全的!如果您的对象没有保留目标,那么在调用其块之前,还有一点工作要做,以保持目标
// -- TheClassName+BlockExtension.h
typedef void (^SoapRequestCompletionBlock)(SoapRequest*);
@interface TheClassName(BlockExtension)
- loginAndConnectWithCredentials:(WSAcredentials*) arg0
dialoutInfo: (WSAdialoutInfo*) arg1;
completionBlock:(SoapRequestCompletionBlock)completionBlock;
@end
// -- TheClassName+BlockExtension.m
// EDITED: If the 'target' object is not retained by the loginAndConnect... then
// we may add it to this collection. In this implementation, a block can
// only be used once.
static NSMutableSet *gSoapTargets = nil;
// These objects serve as targets (with action being completed:) for the original object.
// Because we use one for each request we are thread safe.
@interface MyCustomSoapTargetAction
@property (copy) SoapRequestCompletionBlock block;
- (void) completed:(id)sender;
@end
@implementation MyCustomSoapTargetAction
- (id) init
{
// Objects adds itself to the global collection
if ((self = [super init]))
[gSoapTargets addObject:self];
return self;
}
- (void) completed:(id)sender
{
// Assuming 'sender' is your SoapRequest
if (_block != nil)
_block(sender);
// Object removes itself from global collection when done.
// On return from this method it will likely be released.
[gSoapTargets removeObject:self];
}
+ (void) load
{
gSoapTargets = [NSMutableSet set];
}
@end
@implementation TheClassName(BlockExtension)
- (SoapRequest*) loginAndConnectWithCredentials:(WSAcredentials*) arg0
dialoutInfo: (WSAdialoutInfo*) arg1;
completionBlock:(SoapRequestCompletionBlock)completionBlock
{
MyCustomSoapTargetAction *target = [[MyCustomSoapTargetAction alloc] init];
target.block = completionBlock;
//
// Here we assume that target will be retained.
// If that's not the case then we will need to add it to some collection before
// the call below and have the target object remove itself from it after its
// block has been called.
//
[self loginAndConnect:target action:@selector(completed:) credentials:arg0 dialoutInfo:arg1];
}
@end
*更新:下面是一个基于代码使用此类别的示例:
- (BOOL) serviceIsAvailable
{
return _serviceIsAvailable;
}
- (void) _setServiceIsAvailable:(BOOL)value
{
// This method should probably be private thus the _ prefix
// Do something with the result (set some status, warn user...).
_serviceIsAvailable = value;
}
- (void) checkService
{
WSAcredentials* credentials = [[WSAcredentials alloc] init];
WSAdialoutInfo* dialoutInfo = [[WSAdialoutInfo alloc] init];
if (_service == nil)
_service = [[WSAWebSocketAdapterService alloc] init];
[_service loginAndConnectWithCredentials:credentials
dialoutInfo:dialoutInfo
completionBlock:^(id sender)
{
[self _setServiceIsAvailable:[sender isKindOfClass:[SoapFault class]]];
}];
}
实际上,您不需要源代码。一个类别就可以了。下面是一些示例代码,让您开始学习, 这甚至是线程安全的!如果您的对象没有保留目标,那么在调用其块之前,还有一点工作要做,以保持目标
// -- TheClassName+BlockExtension.h
typedef void (^SoapRequestCompletionBlock)(SoapRequest*);
@interface TheClassName(BlockExtension)
- loginAndConnectWithCredentials:(WSAcredentials*) arg0
dialoutInfo: (WSAdialoutInfo*) arg1;
completionBlock:(SoapRequestCompletionBlock)completionBlock;
@end
// -- TheClassName+BlockExtension.m
// EDITED: If the 'target' object is not retained by the loginAndConnect... then
// we may add it to this collection. In this implementation, a block can
// only be used once.
static NSMutableSet *gSoapTargets = nil;
// These objects serve as targets (with action being completed:) for the original object.
// Because we use one for each request we are thread safe.
@interface MyCustomSoapTargetAction
@property (copy) SoapRequestCompletionBlock block;
- (void) completed:(id)sender;
@end
@implementation MyCustomSoapTargetAction
- (id) init
{
// Objects adds itself to the global collection
if ((self = [super init]))
[gSoapTargets addObject:self];
return self;
}
- (void) completed:(id)sender
{
// Assuming 'sender' is your SoapRequest
if (_block != nil)
_block(sender);
// Object removes itself from global collection when done.
// On return from this method it will likely be released.
[gSoapTargets removeObject:self];
}
+ (void) load
{
gSoapTargets = [NSMutableSet set];
}
@end
@implementation TheClassName(BlockExtension)
- (SoapRequest*) loginAndConnectWithCredentials:(WSAcredentials*) arg0
dialoutInfo: (WSAdialoutInfo*) arg1;
completionBlock:(SoapRequestCompletionBlock)completionBlock
{
MyCustomSoapTargetAction *target = [[MyCustomSoapTargetAction alloc] init];
target.block = completionBlock;
//
// Here we assume that target will be retained.
// If that's not the case then we will need to add it to some collection before
// the call below and have the target object remove itself from it after its
// block has been called.
//
[self loginAndConnect:target action:@selector(completed:) credentials:arg0 dialoutInfo:arg1];
}
@end
*更新:下面是一个基于代码使用此类别的示例:
- (BOOL) serviceIsAvailable
{
return _serviceIsAvailable;
}
- (void) _setServiceIsAvailable:(BOOL)value
{
// This method should probably be private thus the _ prefix
// Do something with the result (set some status, warn user...).
_serviceIsAvailable = value;
}
- (void) checkService
{
WSAcredentials* credentials = [[WSAcredentials alloc] init];
WSAdialoutInfo* dialoutInfo = [[WSAdialoutInfo alloc] init];
if (_service == nil)
_service = [[WSAWebSocketAdapterService alloc] init];
[_service loginAndConnectWithCredentials:credentials
dialoutInfo:dialoutInfo
completionBlock:^(id sender)
{
[self _setServiceIsAvailable:[sender isKindOfClass:[SoapFault class]]];
}];
}
“用块调用”是什么意思?您只需将“操作”块传递给您的函数,并确定它是否/何时应在其中运行。什么是“用块调用”?您只需传递“操作”块,并确定是否/何时应在其内部运行。或仅一个包含错误和结果的块,其中只有一个是非
nil
我有源代码,但它是自动生成的,因此我不想修改它。谢谢你的链接。或者只是一个包含错误和结果的块,其中只有一个是非nil
我有源代码,但它是自动生成的,所以我不想修改它。谢谢你的链接。我还在completed:
的末尾将\u block
属性设置为nil,以避免潜在的内存泄漏。对于完成区块,执行此服务后,没有理由需要继续保留它。将_block设置为nil不需要花费任何费用,因此我们可以继续执行此操作,尽管在ARC环境中,这是不必要的,因为当对象被释放时,块将被释放。@aLevelOfIndirection您能否解释一下有关保留此对象的更多信息目标?我就快到了,但有一个例外,我确信这与此有关。我已经用当前代码更新了原始帖子。谢谢如果调用loginAndConnect的对象在调用块时没有保留目标,则MyCustomSoapTargetAction的实例将被释放。我将编辑我的帖子来处理这种情况。我还将\u block
属性在completed:
末尾设置为nil,以避免潜在的内存泄漏。对于完成区块,执行此服务后,没有理由需要继续保留它。将_block设置为nil不需要花费任何费用,因此我们可以继续执行此操作,尽管在ARC环境中,这是不必要的,因为当对象被释放时,块将被释放。@aLevelOfIndirection您能否解释一下有关保留此对象的更多信息目标?我就快到了,但有一个例外,我确信这与此有关。我已经用当前代码更新了原始帖子。谢谢如果调用loginAndConnect的对象在调用块时没有保留目标,则MyCustomSoapTargetAction的实例将被释放。我会编辑我的帖子来处理这个案子。