Note that there are some explanatory texts on larger screens.

plurals
  1. POPassing blocks to asynchronous methods
    text
    copied!<p>I'm passing a block to an asynchronous method which executes this block later. My app crashes if I don't copy the block before passing it to someMethod:success:failure:</p> <p>Is there a way to copy the blocks in forwardInvocation: instead of copying it before passing it to someMethod:success:failure: ?</p> <p>The flow is <strong>someMethod:success:failure: -> forwardInvocation: -> httpGet:success:failure</strong></p> <p>httpGet:success:failure: executes the success or the failure block depending on the HTTP status code.</p> <pre><code>// AppDelegate.h @interface AppDelegate : UIResponder &lt;UIApplicationDelegate&gt; @property (strong, nonatomic) id response; @property (strong, nonatomic) NSError *error; @end // AppDelegate.m @implementation AppDelegate - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { // The app crashes if the blocks are not copied here! [[MyController new] someMethod:[^(NSString *response) { self.response = response; NSLog(@"response = %@", response); } copy] failure:[^(NSError *error) { self.error = error; } copy]]; return YES; } @end // MyController.h @protocol MyControllerProtocol &lt;NSObject&gt; @optional - (void)someMethod:(void (^)(NSString *response))success failure:(void (^)(NSError *error))failure; @end @interface MyController : NSObject &lt;MyControllerProtocol&gt; @end // MyController.m #import "MyController.h" #import "HTTPClient.h" @implementation MyController - (void)forwardInvocation:(NSInvocation *)invocation { [invocation retainArguments]; NSUInteger numberOfArguments = [[invocation methodSignature] numberOfArguments]; typedef void(^SuccessBlock)(id object); typedef void(^FailureBlock)(NSError *error); __unsafe_unretained SuccessBlock successBlock1; __unsafe_unretained SuccessBlock failureBlock1; [invocation getArgument:&amp;successBlock1 atIndex:(numberOfArguments - 2)]; // success block is always the second to last argument (penultimate) SuccessBlock successBlock = [successBlock1 copy]; [invocation getArgument:&amp;failureBlock1 atIndex:(numberOfArguments - 1)]; // failure block is always the last argument FailureBlock failureBlock = [failureBlock1 copy]; NSLog(@"successBlock copy = %@", successBlock); NSLog(@"failureBlock copy = %@", failureBlock); // Simulates a HTTP request and calls the success block later! [HTTPClient httpGet:@"somerequest" success:successBlock failure:failureBlock]; } - (NSMethodSignature *)methodSignatureForSelector:(SEL)sel { NSMethodSignature *methodSignature = [super methodSignatureForSelector:sel]; return methodSignature; } @end // HTTPClient.h @interface HTTPClient : NSObject + (void)httpGet:(NSString *)path success:(void (^)(id object))success failure:(void (^)(NSError *error))failure; @end // HTTPClient.m #import "HTTPClient.h" @implementation HTTPClient + (void)httpGet:(NSString *)path success:(void (^)(id object))success failure:(void (^)(NSError *error))failure { // Invoke the method. double delayInSeconds = 2.0; dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC)); dispatch_after(popTime, dispatch_get_main_queue(), ^{ success(@"foo"); }); } @end </code></pre> <p>The complete source code can be found here: <a href="https://github.com/priteshshah1983/BlocksWithNSInvocation" rel="nofollow">https://github.com/priteshshah1983/BlocksWithNSInvocation</a></p> <p>Can you please help?</p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload