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 capturedself
, so that the release cycle is broken.