Reputation: 8340
Can anyone please help with ARC and memory-related crashes?
I have class LTRequest
with a member variable that stores a block pointer:
typedef void (^APICallOKBlock)(id);
@interface LTRequest : NSObject
@property (nonatomic, strong) APICallOKBlock okCB;
@end
The code to initialize that variable:
-(void)addOKBlock:(APICallOKBlock)okBlock
{
self.okCB = okBlock;
}
I call the block in case of success:
-(void)apiCallCompletedWithResult:(id)result
{
if(self.okCB != nil)
{
self.okCB(result);
}
}
For reference, the block looks something like this:
APICallOKBlock okBlock = ^(id result)
{
[self handleAPICallCompleted:result];
};
It calls a function defined in the object that scheduled the api call, however that part is not important. Important is what happens when apiCallCompletedWithResult
is called after the api call has been successful. And what happens is that the block gets called but the app crashes shortly afterwards when the request object LTRequest
gets deallocated (SomeAppName is our application):
Thread 6 name: Dispatch queue: com.apple.root.low-priority
Thread 6 Crashed:
0 libobjc.A.dylib 0x300bad9c objc_release + 12
1 libobjc.A.dylib 0x300c6c00 objc_storeStrong + 24
2 SomeAppName 0x00055688 -[LTRequest .cxx_destruct] (LTRequest.m:12)
3 libobjc.A.dylib 0x300bba66 object_cxxDestructFromClass + 50
4 libobjc.A.dylib 0x300bba2c object_cxxDestruct + 8
5 libobjc.A.dylib 0x300b99ac objc_destructInstance + 20
I tried to use unsafe_unretained
instead of strong
to store the block in the LTRequest
object:
@property (nonatomic, unsafe_unretained) APICallOKBlock okCB;
In that case the crash happens exactly in the line with the if:
Thread 0 name: Dispatch queue: com.apple.main-thread
Thread 0 Crashed:
0 libobjc.A.dylib 0x300b9eda objc_retain + 10
1 libobjc.A.dylib 0x300c6bde objc_retainAutoreleasedReturnValue + 34
2 SomeAppName 0x00054f90 -[LTRequest apiCallCompletedWithResult:] (LTRequest.m:84)
3 SomeAppName 0x0002f8aa __29-[LTServerProxy makeAPICall:]_block_invoke_0 (LTServerProxy.m:154)
// file LTRequest.m
line 84 if(self.okCB != nil)
line 85 {
line 86 self.okCB(result);
line 87 }
Am I using the pointer to a block properly and how should I call it to not cause any crashes?
Some info: I am using iOS SDK 5.0, deployment target is 4.0, device iPhone, and ARC is enabled for the whole project.
Upvotes: 3
Views: 14127
Reputation: 34912
You want the property to be copy
rather than retain
:
@property (nonatomic, copy) APICallOKBlock okCB;
Upvotes: 15
Reputation: 7895
You need to copy the block when saving its instance to the class instance.
-(void)addOKBlock:(APICallOKBlock)okBlock
{
self.okCB = [okBlock copy];
}
Upvotes: 2