Assigning a variable inside of a block requires weak reference? - objective-c

So I have the following code:
[serviceHandler getHomeConfigurationData:^(NSDictionary *data){
if (data) {
NSLog(#"The Data: %#", data);
homeConfigData = data;
}
} failure:^(NSError *error, BaseServiceHandler *context){
homeConfigData = Nil;
NSLog(#"Error: %#", error);
}];
in here, homeConfigData is an instance variable in my ViewController. This entire method is done on a background thread. It's possible that the ViewController is deallocated once the completion block returns / is fired. So I'm worried if I'll get an issue when I do the line homeConfigData = data;
How would I handle this?

It's possible that the ViewController is deallocated once the
completion block returns / is fired.
Actually, as it is written now, it is not possible that the ViewController is deallocated by the time the block runs, because both of those blocks retain self as self is used in both blocks (because the instance variable homeConfigData is used, which implicitly means self->homeConfigData).

Like this:
YourClass *__weak weakSelf = self;
[serviceHandler getHomeConfigurationData:^(NSDictionary *data){
if (data) {
NSLog(#"The Data: %#", data);
weakSelf.homeConfigData = data;
}
} failure:^(NSError *error, BaseServiceHandler *context){
weakSelf.homeConfigData = Nil;
NSLog(#"Error: %#", error);
}];
If all of the strong pointers to self become nil, the instance will be deallocated and all the weak pointers, i.e. weakSelf, will become nil. Sending the setHomeConfigData selector to nil will be a noop.

Related

Warning block captures an autoreleasing out-parameter

In a third-party lib I use, I am getting the warning
"Block captures an autoreleasing out-parameter"
What is the problem and how can I fix it?
- (BOOL)register:(NSString *)param error:(NSError **)errPtr
{
__block BOOL result = YES;
__block NSError *err = nil;
dispatch_block_t block = ^{ #autoreleasepool {
NSMutableArray *elements = [NSMutableArray array];
/**** Block captures an autoreleasing out-parameter,
which may result in use-after-free bugs ****/
/* on errPtr */
[self registerWithElements:elements error:errPtr];
}};
if (errPtr)
*errPtr = err;
return result;
}
When you have a method with an indirect non-const parameter (T **param) Clang with ARC automatically qualify such a parameter with __autoreleasing (T *__autoreleasing*). This happens because Clang reasonably assumes, that the calling side is not always required to release such an object, so it puts a requirement on the function to assign autoreleasing objects only. Thus this:
- (void)myMethod:(NSObject **)param {
*param = [NSObject new];
}
Turns into this under ARC:
- (void)myMethod:(NSObject *__autoreleasing*)param {
*param = [[NSObject new] autorelease];
}
This in turn imposes special requirements on the arguments for such a method, so in common scenario where you actually just pass some (strongly retained) object to the function:
NSObject *obj;
[self myMethod:&obj];
ARC in fact makes a temporary autoreleasing argument:
NSObject *__strong obj = nil;
NSObject *__autoreleasing tmp = obj;
[self myMethod:&tmp];
obj = [tmp retain];
What is the problem...
If, instead of (indirectly) passing strongly retained pointer, you pass your own indirect pointer, ARC doesn't make any temporary in between:
NSObject *__autoreleasing obj;
NSObject *__autoreleasing *objPtr = &obj;
[self myMethod:objPtr];
It means that the object "returned" by myMethod: doesn't get retained anymore, thus will be destroyed when current autorelease pool is drained. The same is true if you pass a parameter with the same semantic:
- (void)anotherMethod:(NSObject **)param {
[self myMethod:param];
}
Thus if, for any reason, you decide to wrap the invocation of myMethod: with an autorelease block, the code here ends up with a zombie object:
- (void)anotherMethod:(NSObject **)param {
#autoreleasepool {
[self myMethod:param]; // object was created and assigned to a autoreleasing pointer
} // ref. count of the object reached zero. `*param` refers to a released object
}
The same can potentially happen if you wrap the invocation with a block:
- (void)anotherMethod:(NSObject **)param {
void(^block)(void) = ^{
// "Block captures an autoreleasing out-parameter, which may result in use-after-free bugs" warning appears
[self myMethod:param];
};
block();
}
For this specific implementation no problem will happen, and you could just silence the error by explicitly giving the indirect pointer __autoreleasing qualifier (by which you inform Clang that you are well aware of possible consequences):
- (void)anotherMethod:(NSObject *__autoreleasing*)param {
void(^block)(void) = ^{
[self myMethod:param];
};
block();
}
But now you has to be very careful, because block is a first-party object, which can be retained and called from anywhere and there are countless scenarios where additional autorelease pool is spawned. E.g. this code will case the same zombie-object error:
- (void)anotherMethod:(NSObject *__autoreleasing*)param {
void(^block)(void) = ^{
[self myMethod:param];
};
... some code here ...
#autoreleasepool {
block();
}
}
The same if the autorelease pool is right in the block body:
- (void)anotherMethod:(NSObject **)param {
void(^block)(void) = ^{
#autoreleasepool {
[self myMethod:param];
}
};
block();
}
Having that said, Clangs doesn't warn about the error (it's actually obvious in your case, because you wrap the body of your block with an #autoreleasepool block), it just wants you to double check that you are aware of possible problems (as you can see, it's still possible to implement things like that, but you will have hard time to track all the errors if they appear).
how can I fix it?
This depends on your definition of "fix". You either can remove the autorelease pool block from the body of your block and qualify __autoreleasing parameter explicitly (provided it's merely called in the same thread somewhere in the method):
- (BOOL)register:(NSString *)param error:(NSError *__autoreleasing*)errPtr {
....
dispatch_block_t block = ^{
....
[self registerWithElements:elements error:errPtr];
};
block();
....
}
Or you can introduce another "local" variable to capture and pass it inside a block:
- (BOOL)register:(NSString *)param error:(NSError **)errPtr {
....
__block NSError *err;
dispatch_block_t block = ^{
#autoreleasepool {
....
[self registerWithElements:elements error:&err];
}
};
block();
*errPtr = err;
....
}
This again implies that the block is called synchronously in the method, but not necessarily within the same autorelease pool block. If you want to store the block for later use, or call it asynchronously, then you will need another NSError variable with prolonged lifetime to capture inside the block.

Objective-c block lifetime ARC

I'm confused about the lifetime of a block under ARC. I've written a unit test to demonstrate what is confusing me.
- (void)testBlock {
NSObject *testObject = [[NSObject alloc] init];
CompletionBlock testBlock = ^{ NSLog(#"%#", testObject); };
XCTAssertNotNil(testObject, #"testObject should not be nil");
__weak NSObject *weakTestObject = testObject;
#autoreleasepool {
testObject = nil;
}
XCTAssertNotNil(weakTestObject, #"testObject should be retained by testBlock");
#autoreleasepool {
testBlock = nil;
}
//THIS IS THE FAILING TEST CASE
XCTAssertNil(weakTestObject, #"testObject should have been released when testBlock was released");
}
I'm guessing that this behavior has something to do with how blocks are stored on the stack/heap.
Update!
Setting the block to nil doesn't release the block as I expected because it is on the stack and will not be released until it goes out of scope. Forcing the block to go out of scope fixes my test. Updated code below.
- (void)testBlock {
NSObject *testObject = [[NSObject alloc] init];
__weak NSObject *weakTestObject = testObject;
#autoreleasepool {
CompletionBlock testBlock = ^{ NSLog(#"%#", testObject); };
XCTAssertNotNil(testBlock, #"testBlock should not be nil");
XCTAssertNotNil(testObject, #"testObject should not be nil");
testObject = nil;
XCTAssertNotNil(weakTestObject, #"testObject should be retained by testBlock");
//testBlock goes out of scope here
}
XCTAssertNil(weakTestObject, #"testObject should have been released when testBlock was released");
}
Blocks are created on stack, and only become destroyed when scope exits, pretty much like C++ stack-allocated objects with destructors. These blocks are exempt from reference counting and will ignore retain/release messages. Only after being copied (via Block_copy() function or copy message) they become normal heap-allocated objects that can be retained and released.
In your example, the assert shall start working if you wrap all the code before it in extra curly brackets { }, so that the assert executes after block variable's scope ends.

obj-c weak self in a block: why the 2nd one doesn't need a weak self inside in two similar cases

I finally found my memory bug is caused by referring self strongly in a block. But I don't know why in a similar case, the weak is not needed:
I have a CameraCaptureManager class doing image capture tasks, and a CameraViewController has a strong property of this manager. The manager has weak delegate property pointing back to the controller.
This is where I must use weakSelf in the manager, otherwise -(void)dealloc won't be called:
// in CameraCaptureManager
__weak CameraCaptureManager *weakSelf = self;
void (^deviceOrientationDidChangeBlock)(NSNotification *) = ^(NSNotification *notification) {
UIDeviceOrientation deviceOrientation = [[UIDevice currentDevice] orientation];
[weakSelf updateVideoOrientation:deviceOrientation];
};
self.deviceOrientationDidChangeObserver = [notificationCenter addObserverForName:UIDeviceOrientationDidChangeNotification
object:nil
queue:nil
usingBlock:deviceOrientationDidChangeBlock];
The manager holds the deviceOrientationDidChangeObserver strongly, so weakSelf is needed to break the memory retain cycle. That's fine, I got that... but I find I don't have use weakSelf in a similar case in the same class:
[self.stillImageOutput captureStillImageAsynchronouslyFromConnection:captureConnection
completionHandler:^(CMSampleBufferRef imageDataSampleBuffer, NSError *error){
UIImage *image = nil;
if (imageDataSampleBuffer != NULL) {
NSData *imageData = [AVCaptureStillImageOutput jpegStillImageNSDataRepresentation:imageDataSampleBuffer];
image = [[UIImage alloc] initWithData:imageData];
}
if ([self.delegate respondsToSelector:#selector(captureManager:capturedStillImage:)]) {
[self.delegate captureManager:weakSelf capturedStillImage:image];
}
}];
The manager also holds the stillImageOutput strongly, but why I can use the strong "self" in the completion block? The manager object gets dealloc with this strong self inside the block. I'm confused, please shed some light.
Also do I need to use weakSelf in the 2nd case even when it won't cause any retain cycle?
In your second code example you have a temporary retain cycle. When the completionHandler block has been called, the block is released and with it the captured self, so
that the release cycle is broken.

memory leak when using callback

I'm having an issue with memory management when dealing with callbacks and async code in objective c.
I cant seem to find a way to release the instance that the callback is set on.
For example:
MyClass *myArchive = [[MyClass alloc] init] ;
[myArchive callBack:^(RKObjectLoader* objectLoader, id object ) {
NSLog(#"success");
} fail:^(RKObjectLoader* objectLoader, NSError* error) {
NSLog(#"failed");
}];
[myArchive searchArchive:words:paging];
The problem being that I don't know when or how to release the instance *myArchive. Using Instruments within xcode to profile my code I always get a leak here. The function searchArchive performs an async request to a server using restkit. I wont reference the instance from within the callback as I heard this causes a retain cycle and I have done some reading about using __block and other c approaches to avoid retain cycles which is all fine but as it stands now with no actual code happening within the callback how do I release the *myArchive instance. anyone able to explain how I should deal with this within objective-c?
EDIT:
This is where I set the callback in myclass
// Sets internal backs on this object which basically wrap the delegate
//
- (void)callBack: (void (^)(RKObjectLoader* objectLoader, id object))success
fail: (void (^)(RKObjectLoader* objectLoader, NSError* error))fail {
//sanity check
NSAssert(_currentDelegate != self, #"Delegate is another object. Can not set callback");
// store our callback blocks in the instance
_success = [success copy] ;
_fail = [fail copy] ;
}
and then release _success and _fail in dealloc
and within the #interface
#interface myClass : NSObject<RKObjectLoaderDelegate> {
// holds the block callback for "success"
void (^_success)(RKObjectLoader* objectLoader, id object);
// holds the block callback for "fail"
void (^_fail)(RKObjectLoader* objectLoader, NSError* error);
}
I hope this gives more insight into what I'm doing wrong.
EDIT 2:
Ok I'm beginning to see the errors now:
-(void)retrieveGallery{
//create call back for async and deal with the result
[_galleryItems callBack:^(RKObjectLoader* objectLoader, NSArray *objects) {
//success happy days. do a bunch of code here that does not cause leaks
} fail:^(RKObjectLoader* objectLoader, NSError* error) {
//retry the attempt to retrieve gallery data from the server
_retryCount++;
if (_retryCount < _maxRetryCount) {
[self retrieveGallery];
}
}];
//read the collection of gallery items from server
[_galleryItems readGallery];
}
The only actual memory leaks are when the callback catches a fail for what ever reason and then calls the [self retrieveGallery] function from within callback to attempt again. this is what is causing the leak so I'm guessing that is a big no no. How should I attempt the function (retrieveGallery in this case) again.
Memory management isn't really any different because you are using an asynchronous callback. myArchive should be a property of whatever class you are doing this in. You want it to stick around until the task is complete, right?
#property (retain) MyClass *myArchive;
Then..
myArchive = [[MyClass alloc] init];
void (^on_success_callback)(void) = ^(void){
NSLog(#"success");
self.myArchive = nil;
};
You need to make sure you are managing the callbacks properly, i.e. copying them from the stack and releasing them when you are done.
If you have retains and releases in your code you probably aren't using the accessor methods properly.

Calling [self methodName] from inside a block?

I've just run into blocks and I think they are just what I'm looking for, except for one thing: is it possible to call a method [self methodName] from within a block?
This is what I'm trying to do:
-(void)someFunction{
Fader* fader = [[Fader alloc]init];
void (^tempFunction)(void) = ^ {
[self changeWindow:game];
//changeWindow function is located in superclass
};
[fader setFunction:tempFunction];
}
I've been searching for a couple of days and I can't find any evidence that this is possible.
Is this at all possible, or am I trying to use blocks for something they aren't meant for?
The reason I'm using blocks is that I've created a Fader class, and I want to store a block for it to execute when it finishes fading out.
Thank you
EDIT:
Okay, I added in the suggestion, but I'm still getting an EXC_BAD_ACCESS error...
-(void)someFunction{
Fader* fader = [[Fader alloc]init];
__block MyScreen* me = self;
void (^tempFunction)(void) = ^ {
[me changeWindow:game];
//changeWindow function is located in superclass
};
[fader setFunction:tempFunction];
[fader release];
}
Maybe I'm not allowed to give fader the function...?
Yes, you can do this.
Note, however, that the block will retain self. If you end up storing this block in an ivar, you could easily create a retain cycle, which means neither would ever get deallocated.
To get around this, you can do:
- (void) someMethodWithAParameter:(id)aParameter {
__block MySelfType *blocksafeSelf = self;
void (^tempFunction)(void) = ^ {
[blocksafeSelf changeWindow:game];
};
[self doSomethingWithBlock:tempFunction];
}
The __block keyword means (among other things) that the referenced object will not be retained.
The accepted answer is outdated. Using __block in that case can cause errors!
To avoid this problem, it’s best practice to capture a weak reference to self, like this:
- (void)configureBlock {
XYZBlockKeeper * __weak weakSelf = self;
self.block = ^{
[weakSelf doSomething]; // capture the weak reference
// to avoid the reference cycle
}
}
Please, look at Apple Documentation - Avoid Strong Reference Cycles when Capturing self
for more details.
__block CURRENTViewController *blocksafeSelf = self;
[homeHelper setRestAsCheckIn:strRestId :^(NSObject *temp) {
[blocksafeSelf YOURMETHOD:params];
}];
Is it possible to call a method [self methodName] from within a block?
Yes, why not. If your tempFunction is an instance method, you can do it. The called method should be accessible is the only restriction.
Consider this (which I think is the best practice)
#implementaion ViewController
- (void) viewDidLoad {
__weak typeof(self) wself = self;
[xxx doSomethingUsingBlock: ^{
__strong typeof(wself) self = wself;
[self anotherMessage];
}];
}
#end
Moreover, You can define wrapper macros.
#define MakeWeakSelf __weak typeof(self) wself = self
#define MakeStrongSelf __strong typeof(wself) self = wself
I wonder whether you [fader setFunction:tempFunction]; then is synchronous or asynchronous.
blocks push onto stack.so in MRR,if you don't retain it,it will pop off.
-(void)someFunction{
Fader* fader = [[Fader alloc]init];
void (^tempFunction)(void) = ^ {
[self changeWindow:game];
//changeWindow function is located in superclass
};
[fader setFunction:tempFunction];
//if the tempFunction execute there will be right.
}//there the tempFunction pop off
//....some thing go on
//execute the tempFunction will go wrong.