Correct way to pass NSError from URLSession - objective-c

I have Network layer class, which has method with URL request. Seems like this:
- (void)networkRequestWithError:(NSError *__strong *)responseError
andCompletion:(void (^)(NSData*))completion
{
NSURL *url = ...
NSURLSessionDataTask *dataTask = [NSURLSession.sharedSession
dataTaskWithURL:url
completionHandler:^(NSData *data,
NSURLResponse *response,
NSError *error) {
// *responseError = error; for real errors
*responseError = [NSError errorWithDomain:#"1"
code:1
userInfo:#{}];
completion(data);
}];
[dataTask resume];
}
#end
I create instance of this network layer in controller and I want to handle error in completion block:
__block NSError *responseError;
[self.networkService networkRequestWithError:&responseError
withCompletion:^(NSData*) {
if (responseError != nil) {
NSLog(#"%#",responseError.localizedDescription);
} else {
//Some action with data. No matter
}
}];
Problem: responseError has some value in dataTask completion scope (when I init it), but in my completion block in controller it always nil. I don't have any idea why.

This is an asynchronous method. Don’t set the response error by indirection. Do exactly what dataTaskWithURL does: pass it as another parameter into the completion block.
- (void)networkRequestWithCompletion:(void (^)(NSData*, NSError*))completion

For a technical explanation of why your code didn't work, it has to with the fact that __block variables can be moved, and thus getting a pointer to it at one point doesn't mean that the pointer still points to the variable later. You have to be careful when taking the address of a __block variable.
As an optimization, blocks start out on the stack, and __block variable also start out in a special structure on the stack. When some code need to store the block for use after the current scope, it copies the block, which causes the block to be moved to the heap if it isn't already there (since things on the stack may not live beyond the current call). Moving a block to the heap also causes any __block variables that the block captures to be moved to the heap if it isn't already there (again, since it needs to be on the heap to outlive the current call).
Normally, when you get or set a __block variable, the compiler translates that into several pointer lookups behind the scenes to access the real location of the __block variable, so it transparently works, no matter if it's on the stack or heap. However, if you take the address of it to get a pointer, as in &responseError, you only get the address of it as the variable currently is, but it does not get updated if the variable is moved.
So what is happening in your case is that the __block variable responseError in your second piece of code starts out on the stack, and when you do &responseError, you get a pointer to its location on the stack. This pointer is passed into -networkRequestWithError:withCompletion:, and this pointer (confusingly also called responseError) is then captured into the block it creates and passes into -[NSURLSession dataTaskWithURL:completionHandler:].
At the same time, the __block variable responseError in your second piece of code is captured by the block you pass into -networkRequestWithError:withCompletion:, and this block (called completion) is then captured by the block you pass into -[NSURLSession dataTaskWithURL:completionHandler:]. That is an asynchronous operation, so they copy the block, which copies the first block, which moves the blocks, as well as the __block variable responseError, to the heap.
By the time the completion handler of -[NSURLSession dataTaskWithURL:completionHandler:] is called asynchronously, the stack frame where the original __block variable responseError was created has ended, and the pointer that we captured (called responseError in -networkRequestWithError:withCompletion:, which is a pointer to the original __block variable responseError on the stack) is a dangling pointer. Assigning to the thing pointed to by that pointer is undefined behavior, and may actually be overwriting some unrelated variables on the stack. On the other hand, the actual __block variable responseError on the heap is not changed, and still holds the value it originally held (nil).
In your second piece of code, if you printed out the address of responseError (&responseError) before the block and within the block, you will see that they are different, demonstrating that it was moved.

Related

Why does ARC only sometimes retain a __block out pointer?

1) Why does this retain its __block var:
{
void (^blockWithOutPointer)(NSObject * __autoreleasing *) = ^(NSObject * __autoreleasing * outPointer) {
*outPointer = [NSObject new];
};
NSObject * __block blockVar1;
dispatch_after(dispatch_time(DISPATCH_TIME_NOW,
(int64_t)(1 * NSEC_PER_SEC)),
dispatch_get_main_queue(),
^{
NSLog(#"blockVar1: %#",
blockVar1);
// prints non-nil. WHY????
});
blockWithOutPointer(&blockVar1);
}
2) But this doesn't?
void (^blockWithOutPointerThatDispatchesLater)(NSObject * __autoreleasing *,
dispatch_block_t) = ^(NSObject * __autoreleasing * outPointer,
dispatch_block_t block) {
dispatch_after(dispatch_time(DISPATCH_TIME_NOW,
(int64_t)(1 * NSEC_PER_SEC)),
dispatch_get_main_queue(),
block);
*outPointer = [NSObject new];
};
{
NSObject * __block blockVar2;
blockWithOutPointerThatDispatchesLater(&blockVar2,
^{
NSLog(#"blockVar2: %#",
blockVar2);
});
// prints nil, which is expected.
}
3) If I instead use an __autoreleasing variable as my out pointer destination, and then assign that variable to my __block pointer, everything works fine.
{
NSObject * __autoreleasing autoreleasingVar;
NSObject * __block blockVar3;
blockWithOutPointerThatDispatchesLater(&autoreleasingVar,
^{
NSLog(#"blockVar3: %#",
blockVar3);
});
blockVar3 = autoreleasingVar;
// prints non-nil, which is expected.
}
I've read CRD's answer about ARC pointer-to-pointer issues, it makes sense that #2 would print nil because ARC assumes that blockVar2 is __autoreleasing, and doesn't retain its value. Thus, in #3, when we assign autoreleasingVar to blockVar3, ARC properly retains the value. However, there is no such assignment for #1. Why does #1 retain its value?
Even more amazingly, #1 is unaffected if I wrap the out-pointer assignment in an #autoreleasepool:
{
void (^blockWithOutPointer)(NSObject * __autoreleasing *) = ^(NSObject * __autoreleasing * outPointer) {
#autoreleasepool {
*outPointer = [NSObject new];
}
};
NSObject * __block blockVar1;
dispatch_after(dispatch_time(DISPATCH_TIME_NOW,
(int64_t)(1 * NSEC_PER_SEC)),
dispatch_get_main_queue(),
^{
NSLog(#"blockVar1: %#",
blockVar1);
// still prints non-nil. WHY???
});
blockWithOutPointer(&blockVar1);
}
Whereas #3 crashes, as expected since the #autoreleasepool released the out-pointer's object, and I guess ARC doesn't set __autoreleasing variables to nil.
void (^blockWithOutPointerThatDispatchesLater)(NSObject * __autoreleasing *,
dispatch_block_t) = ^(NSObject * __autoreleasing * outPointer,
dispatch_block_t block) {
dispatch_after(dispatch_time(DISPATCH_TIME_NOW,
(int64_t)(1 * NSEC_PER_SEC)),
dispatch_get_main_queue(),
block);
#autoreleasepool {
*outPointer = [NSObject new];
}
};
{
NSObject * __autoreleasing autoreleasingVar;
NSObject * __block blockVar3;
blockWithOutPointerThatDispatchesLater(&autoreleasingVar,
^{
NSLog(#"blockVar3: %#",
blockVar3);
// crashes on the NSLog!
});
blockVar3 = autoreleasingVar;
}
I filed a radar about this.
You have discovered a "feature" of the block implementation and (at least for cases 1 & 2, I haven't checked further) it is nothing to do with __autoreleasing per se.
First let's look at your case 1. You seem surprised this prints a non-nil value. It works exactly as expected:
blockWithOutPointer(&blockVar1); executes, assigning a value to blockVar1; then
the block ^{ NSLog(#"blockVar1: %#", blockVar1); } is executed by GCD and the stored by (1) is printed.
(Note: You can removed the __autoreleasing qualifiers and it will work the same as this is the inferred mode for pass-by-writeback parameters.)
Now your case 2. This is where you hit the "feature":
In Objective-C objects are heap allocated; and
Objective-C blocks are objects; so
Ergo blocks are heap allocated...
Except when they are not...
As an optimisation the block specification allows blocks and their captured __block variables to be stack allocated and only moved onto the heap when their lifetime needs to be longer than the stack frame are in.
As an optimisation it should (a) be essentially invisible to the programmer - apart from any perf benefit and (b) not change the semantics in anyway. However Apple decided to initially introduce it as a "programmer assisted optimisation" and have then slowly improved matters.
The behaviour of your case 2 is all down to when the block and __block variable get copied onto the heap. Let's look at the code:
NSObject * __block blockVar2;
This declares blockVar2 to have __block storage duration, which allows a block to alter the value of this locally declared variable. At this point the compiler does not know whether a block may access it, in which case blockVar2 will need to be on the heap, or whether it won't, in which case it may be on the stack.
The compiler decides it prefers the stack and allocates blockVar2 there.
blockWithOutPointerThatDispatchesLater(&blockVar2,
Now the compiler needs to pass the address of blockVar2 as the first argument, the variable is currently on the stack, and the compiler emits code to calculate its address. That address is on the stack.
^{
NSLog(#"blockVar2: %#",
blockVar2);
});
Now the compiler gets to the second argument. It sees the block, that the block accesses blockVar2, and that blockVar2 is qualified by __block so it must capture the variable itself and not the variables value.
The compiler decides the block should go on the heap. For this to work it needs to migrate blockVar2 onto the heap, so it does that along with its current value nil...
Oops!
The first argument is the address of the original blockVar2 on the stack, while the second argument is a block which in turn references the cloned blockVar2 on the heap.
When the code is executed blockWithOutPointerThatDispatchesLater() allocates an object and stores its address in the stack blockVar2; then GCD executes the delayed block which prints of the value of the heap blockVar2, which is nil.
A “Fix”
Just change your code to:
NSObject * __block blockVar2;
dispatch_block_t afterBlock = ^{
NSLog(#"blockVar2: %#", blockVar2);
};
blockWithOutPointerThatDispatchesLater(&blockVar2, afterBlock);
i.e. pre-calculate the second argument expression. Now the compiler sees the block before it sees &blockVar2, moves the block and blockVar2 to the heap, and the value generated for &blockVar2 is the address of the heap version of blockVar2.
Expanded Conclusion: Bug or Feature?
The original answer simply stated this is clearly a bug, not a feature, and suggest you file a bug report, noting it's been reported before but another report won't harm.
However that might be a little unfair, yes it is a bug, the question is what the bug actually is. Consider:
In (Objective-)C variables, allocated on the stack or statically, and allocated dynamic memory blocks do not move during their lifetime.
Compiler optimisations in general should not alter the meaning or correctness of a program.
Apple has implemented a compiler optimisation – storing blocks and captured __block variables on the stack – in a way which can move __block attributed variables during their lifetime and in doing so the meaning and correctness of a program can be altered.
The result is a simple re-ordering of program statements in a way which should not alter program meaning or correctness in fact does. This is bad!
Given the history of the optimisation, as implemented by Apple, which by-design relied on programmer assistance (though it has since been made more automatic) for its correctness this could simply be seen as another “feature” of the chosen implementation.
Recommendation
Never, ever, apply the address-of (&) operator to a variable with __block storage duration. If may work if you do, but it just as easily may not.
If you need to use a __block variable as a pass-by-writeback argument then copy it to a local temporary first, make the call, and finally copy it back again.
HTH
There's probably a misconception in 1):
If a variable will be imported into a block, which is marked with __block the compiler generates a helper struct containing various fields and the variable corresponding to the given source. That is, there's no pointer blockVar1, instead there's a whole struct instead.
If a block imports this variable and needs to be copied (for example, when asynchronously submitted) it also "moves" this helper struct onto the heap before "moving" the block itself onto the heap.
This statement
NSObject * __block blockVar1;
will initialise the helper struct which embeds the actual variable and initialises it to nil. The corresponding address of the variable points into the stack.
When the compiler parses this statement:
dispatch_after(dispatch_time(DISPATCH_TIME_NOW,
(int64_t)(1 * NSEC_PER_SEC)),
dispatch_get_main_queue(),
^{
NSLog(#"blockVar1: %#",
blockVar1);
// prints non-nil. WHY????
});
The compiler generates code for the compound statement, specifically it creates a struct representing the block which initially exists on the stack, too. Since this block requires to be moved to the heap before executing dispatch_async, it also moves the helper struct onto the heap in subsequently generated code.
Additionally, since the imported variable is a NSObject pointer, it also assigns function pointers (located in the helper struct) which "keep" and "dispose" the object, which will be called when the helper struct is "moved" to the heap, respectively when it is destroyed.
When you finally execute this statement
blockWithOutPointer(&blockVar1);
the address of the variable has already been changed: the variable is now located on the heap (since the helper struct has been "moved" to the heap") and exists as long as the block.
Now, to the point where you declare (and define) the following block:
void (^blockWithOutPointer)(NSObject * __autoreleasing *)
What causes gripes here is the __autoreleasing modifier, specifically Storage duration of __autoreleasing objects:
That is, __autoreleasing can only be applied to variables with automatic storage duration.
Edit:
This would assume that the given variable is on the stack. However, it is located on the heap. Thus, your program is illformed and the behaviour is undefined.
Regarding the __autoreleasing storage qualifier, the code sample 1) is correct (the _autoreleasing storage qualifier refers to a temporary that is created when passing the variable as a parameter, see comments below).
What I've said previously above should be correct, and what the user is experiencing is thus expected.
For further reference see: http://clang.llvm.org/docs/Block-ABI-Apple.html
However:
There's still a subtle potential issue with a "data race": the statement
blockWithOutPointer(&blockVar1);
will modify a pointer variable which is located on the heap, while executing on the current thread. Later, on the main thread the same variable will be read. Unless current thread equals main thread, this exhibits a classic data race.
While this is not the question and no a complete answer - it shows, how quickly such code becomes more complex than desired and I would recommend to strive for simpler, comprehensible code.
End Edit
I haven't analysed the other code samples
- but at the first glance it seems, using __autoreleasing leads also to an illformed program.

Why need to copy the objective-c handler before cast it to void* type?

I want to simulate the NSAlert member function which only exist on 10.9.
- (void)beginSheetModalForWindow:(NSWindow *)sheetWindow completionHandler:(void (^)(NSModalResponse returnCode))handler NS_AVAILABLE_MAC(10_9);
The code is as following:
-(void)compatibleBeginSheetModalForWindow: (NSWindow *)sheetWindow
completionHandler: (void (^)(NSInteger returnCode))handler
{
void *handlerValue = (__bridge void*) [handler copy];
[self beginSheetModalForWindow: sheetWindow
modalDelegate: self
didEndSelector: #selector(blockBasedAlertDidEnd:returnCode:contextInfo:)
contextInfo: handlerValue];
}
-(void)blockBasedAlertDidEnd: (NSAlert *)alert
returnCode: (NSInteger)returnCode
contextInfo: (void *)contextInfo
{
void(^handler)(NSInteger) = (__bridge typeof(handler)) contextInfo;
handler(returnCode);
[handler release];
}
I need to copy the handler before cast it to void*, else it will crash, if I change it to following line:
void *handlerValue = (__bridge void*) handler;
And by check the handler in blockBasedAlertDidEnd:returnCode:contextInfo:, it is an incorrect value.
Even I call [handler retain] before cast to void* it doesn't work.
It is quite confuse to me, so why I need to copy it?
This is because blocks are created on the stack and not the heap. So when the stack pointer moves on the memory in that stack frame is returned and the block is lost. Thats why you always should copy blocks and not retain them. When you run copy on a block the new copy is allocated on the heap and therefor don't get removed.
Peter Segerblom covered the basics of it. In the current implementation, there are 3 kinds of blocks. Blocks that don't capture local variables are global blocks; there is just one instance that has static lifetime. Blocks that do capture local variables start out as objects on the stack; and copying it will return a block on the heap. Copying heap or global blocks will simply return the same instance.
Basically, a block passed into your function could be a stack block or not. A stack block is only valid for the current function call. Since it could be a stack block, you must use a copy of it if you want to store it somewhere that outlives the current function call. This is the contract for functions that take a block parameter.
Now, if all your function does with this block is pass it to another function, do you need to pass a copy? If this function parameter is of block type, then no, because if this function needs to keep the block around for later, then it is responsible for copying it (according to the contract above). So you don't need to worry about it. But, if you pass it to a function that is not of block type (e.g. -[NSMutableArray addObject:]), then that function does not know to potentially copy it (it doesn't even know it's a block). In that case, you will have to pass a copy if that function keeps the object around for later. This is the case with the function you are passing to here.

NSDictionary of Blocks as argument cause overflow

I understand blocks are objective c objects and can be put in NSDictionary directly without Block_copy when using ARC. But I got EXC_BAD_ACCESS error with this code:
- (void)viewDidLoad
{
[super viewDidLoad];
[self method1:^(BOOL result){
NSLog(#"method1WithBlock finished %d", result);
}];
}
- (void) method1:(void (^)(BOOL))finish{
NSDictionary *dict = [NSDictionary dictionaryWithObjectsAndKeys:^(NSData *rcb){
finish(YES);
}, #"success",
^(NSError *error){
finish(NO);
}, #"failure", nil];
[self method2:dict];
}
- (void) method2:(NSDictionary *)dict{
void (^success)(NSData *rcb) = [dict objectForKey:#"success"];
success(nil);
}
If I change method1: to this, no error raised.
- (void) method1:(void (^)(BOOL))finish{
void (^success)(NSData *) = ^(NSData *rcb){
finish(YES);
};
void (^failure)(NSError *error) = ^(NSError *error){
finish(NO);
};
NSDictionary *dict = [NSDictionary dictionaryWithObjectsAndKeys:success, #"success",
failure, #"failure", nil];
[self method2:dict];
}
Can anybody explain why I have to use automatic variables to store the blocks before putting them to dictionary ?
I am using iOS SDK 6.1.
According to the "Transitioning to ARC Release Notes", you have to copy a block stored
in a dictionary (emphasis mine):
Blocks “just work” when you pass blocks up the stack in ARC mode, such
as in a return. You don’t have to call Block Copy any more.
You still need to use [^{} copy] when passing “down” the stack into
arrayWithObjects: and other methods that do a retain.
The second method works "by chance" because success and failure are a
__NSGlobalBlock__ and not a "stack based block" that needs to be copied to the heap.
I understand blocks are objective c objects and can be put in NSDictionary directly without Block_copy when using ARC.
No, they're not common objects. When you create a block it is on the stack, and it doesn't matter of what is it's retain count, when you exit form the function it will be popped from the stack. Copy it to make it stay alive.
You must copy blocks before passing them to a method when 1) the block will be stored for longer than the duration of the call, and 2) the parameter you are passing it to is a normal object pointer type (i.e. id or NSObject *) instead of a block type.
This is the case for your call. dictionaryWithObjectsAndKeys: stores the argument in the resulting dictionary, and it simply expects normal object pointer arguments (of type id), and does not know whether you are passing blocks or not.
The reason for the second condition I said is because if the method parameter already takes a block type (e.g. for any completion handler parameters), then that method is already aware of the special memory management requirements of blocks, and therefore will take responsibility for copying the block if it needs to store it. In that case the caller doesn't need to worry about it. However, in your case, you are passing it to a general method that doesn't know it's getting a block, and thus doesn't know to copy it. So the caller must do it.
Can anybody explain why I have to use automatic variables to store the
blocks before putting them to dictionary ?
About this, your second example happens to work because recent versions of the ARC compiler is super conservative about blocks and inserts copies whenever you assign it to a block type variable. However, this is not guaranteed by the ARC specification, and is not guaranteed to work in the future, or in another compiler. You should not rely on this behavior.

Chaining Completion Blocks

I have two instances of different classes who both need to add a completion block to a particular operation. I'll try to explain the problem generically rather than having to explain everything my app is attempting to do.
A view controller is calling into an instance of a resource manager class for it to save a resource. The resource manager then calls into the class of the resource to be saved to get a network operation for the save.
The instance of the resource creates the operation and gives it a completion block that will affect the state of the resource when it fires.
This is where my problem is - the resource class also needs to add a completion block to this operation in order for the view controller to be informed of the success or failure of the save.
Here's a snippit of the save method on the manager:
-(void)save:resource withCompletion:completion
{
.
.
.
NSOperation *operation = [resource operationForSave];
NSOperation __weak *weakOperation = operation;
void(^__weak resourceCompletion)(void)= operation.completionBlock;
[operation setCompletionBlock:^{
if (resourceCompletion) {
resourceCompletion();
}
if (completion) {
if (weakOperation.error) {
completion(NO, operation.error);
}
else {
completion(YES, nil);
}
}
}];
.
.
.
// add the operation to a network operation queue
}
While I think this will technically work, I'm not crazy about it. It feels pretty funky. I would prefer to have one block encapsulating the second block, but this isn't possible because the view controller and the resource are creating their own completion blocks, and the manager class is the one that has to smash them together.
Is there a more elegant way to chain these two completion blocks together in this situation, or is my current method of creating a block to contain the original two blocks the best I'm going to get?
Any input would be great appreciated.
The code you posted will probably not work. When you replace the operation's completion block with your own block, you're probably removing the only strong reference to the original completion block (set by the resource). So your resourceCompletion variable, being weak, will become nil by the time setCompletionBlock: returns.
Just making resourceCompletion strong should fix the problem. But if you want to do it in a cleaner way, modify the operationForSave message (on the resource) to take a completion block itself:
__block NSNetworkOperation *operation = [resource operationForSaveWithCompletion:^{
NSError *error = operation.error;
completion(error == nil, error);
// Break the retain cycle between this block and the operation object.
operation = nil;
}];
And make it the job of the resource's own internal completion block to call the completion block you provide.
If you don't want to or can't modify the resource's API, you can still simplify your code by eliminating the weak references:
__block NSNetworkOperation *operation = [resource operationForSave];
__block void (^priorCompletion)(void) = operation.completionBlock;
operation.completionBlock = ^{
if (priorCompletion) {
priorCompletion);
// Break possible retain cycle.
priorCompletion = nil;
}
NSError *error = operation.error;
completion(error == nil, error);
// Break the retain cycle between this block and the operation object.
operation = nil;
};
Also, I sincerely hope you don't really have a class named NSNetworkOperation, because Apple reserves the NS prefix (and all other two-letter prefixes) for its own use.

Why does Objective-C block still work without copying it to the heap?

I have a simple method in my class:
- (void)getFormWithBlock:(DataCenterResultBlock)block {
[SomeClass doSomeLongOperationWithParam:someParam
completionBlock:^(NSData *data, NSURLResponse *response) {
//Success
block(aVar, YES);
} errorBlock:^(NSError *error) {
//Failed
block(nil, NO);
}];
}
I read that you should copy blocks to the heap if you are doing something asynchronously because they are allocated on stack and once the call tree rewinds it will be gone.
But here, I am not copying it to heap but still I get no crash. Why?
Thanks
Block variables are copied to the heap automatically by ARC compilers:
7.5. Blocks
...
__block variables of retainable object owner type are moved off the stack by initializing the heap copy with the result of moving from the stack copy.
EDIT I think I misunderstood the question: you asked about block objects themselves, not block variables. The answer in this case is slightly different, but it boils down to the same this: ARC does the correct thing automatically.
ARC knows that block literals must be copied if they're used after the current scope returns. Non-ARC code needs to explicitly copy and autorelease returned blocks:
return [[^{
DoSomethingMagical();
} copy] autorelease];
With ARC, this simply becomes:
return ^{ DoSomethingMagical(); };
(from here)
[SomeClass doSomeLongOperationWithParam:completionBlock:errorBlock:] should be copying the completion and error blocks.
If you look at the implementation of that method, it is probably doing the right thing and copying the block that you passed in. ARC or no ARC, that method should copy those blocks.