1

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?

X.Y.
  • 13,726
  • 10
  • 50
  • 63

1 Answers1

4

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.

Martin R
  • 529,903
  • 94
  • 1,240
  • 1,382
  • Thanks Martin, you helped me a couple of times! That explains my confusion! Is it a good practice to still use weakSelf in a temporary retain cycle? – X.Y. Jul 28 '13 at 18:02
  • 2
    @XiaochaoYang: It depends! Using a strong reference (as you do) ensures that `self` is "kept alive" until the completion block is executed. With a weak reference, `self` could be destroyed before the block is called. So it depends on whether you want the action in the block executed in any case or not. – Martin R Jul 28 '13 at 18:09
  • "When the completionHandler block has been called, the block is released" What makes you think that the block is released? – newacct Jul 29 '13 at 03:20
  • @newacct It's because the block only run once for completion, while the observer block is around in the memory dealing future notifications. – X.Y. Aug 01 '13 at 00:38