Sending 'NSError * const __strong *' to a parameter of type 'NSError * __ autoreleasing *' changes the properties of saving / freeing the pointer

This question is similar to ios NSError types , but the solution described there does not work, and I believe that this is not quite what I need.

I have a method that accepts an asynchronous call and then calls the completion block. When I try to pass NSError ** to the completion block, I get this error:

Sending 'NSError * const __strong *' to a parameter of type 'NSError * __ autoreleasing *' changes the properties of saving / freeing the pointer

The code is as follows:

+(void) agentWithGUID:(NSString *) guid completion:(void (^)(AKAgentProfile * agentProfile, NSError ** error)) completionBlock { dispatch_queue_t requestQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); dispatch_async(requestQueue, ^{ NSString * parameterizedUrl = [AKAgentProfileEndPoint stringByAppendingString:guid]; NSURL *url = [NSURL URLWithString:parameterizedUrl]; NSData *data = [NSData dataWithContentsOfURL:url]; NSError * error = nil; AKAgentProfile * agentProfile = [[[AKAgentFactory alloc] init] agentProfileWithData:data error:&error]; dispatch_async(dispatch_get_main_queue(), ^{ completionBlock(agentProfile,&error); }); }); } 
+5
source share
3 answers

Your arguments to the completion block are complete stupidity.

The call stack has the variable NSError * err.

Then you try to pass the error address to the completion block, which will be called in the main thread. By the time the termination block is called, your function has long returned, and the error is garbage. If the termination unit tried to save something there, it will store NSError *, where some long variable ERR has been on the stack, most likely some valuable data will be overwritten by a completely unrelated method.

It just doesn't work with callback blocks.

+5
source

Pass the error by value, not by reference, that is, replace the block signature with void (^)(AKAgentProfile * agentProfile, NSError * error) and skip error instead of &error .

+5
source

You have an error defined as an argument in

 +(void) agentWithGUID:(NSString *) guid completion:(void (^)(AKAgentProfile * agentProfile, NSError ** error)) completionBlock 

and then again in the block, I suggest you rename one in the block, for example:

 +(void) agentWithGUID:(NSString *) guid completion:(void (^)(AKAgentProfile * agentProfile, NSError ** error)) completionBlock { dispatch_queue_t requestQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); dispatch_async(requestQueue, ^{ NSString * parameterizedUrl = [AKAgentProfileEndPoint stringByAppendingString:guid]; NSURL *url = [NSURL URLWithString:parameterizedUrl]; NSData *data = [NSData dataWithContentsOfURL:url]; NSError * err = nil; AKAgentProfile * agentProfile = [[[AKAgentFactory alloc] init] agentProfileWithData:data error:&error]; dispatch_async(dispatch_get_main_queue(), ^{ completionBlock(agentProfile,&err); }); }); } 
-1
source

Source: https://habr.com/ru/post/1210258/


All Articles