NSNotificationCenter with blocks considered harmful
sealedabstract.com
NSNotificationCenter with blocks considered harmful
1–10 of 39 posts
Re: NSNotificationCenter with blocks considered harmful
#2Re: NSNotificationCenter with blocks considered harmful
#3This really applies equally to any block that captures self. Blocks are, IMHO, the one place where ARC really falls down versus garbage-collection.
The only thing that makes this case confusing is that self only holds the block implicitly (via the notification center instead of any obvious ivar). Otherwise it's a design pattern that every reference counted language user must understand to avoid memory leaks. Weak references to self in blocks are a very common design pattern that all Objective-C programmers should know.
Re: NSNotificationCenter with blocks considered harmful
#4The only thing that surprised me was the reference cycle in NSAssert. Then again, given Apple's poor regard for TDD, that shouldn't surprise me.
Re: NSNotificationCenter with blocks considered harmful
#5There's nothing really magical about this – don't cause retain cycles, everyone knows __block semantics changed with ARC, keep the returned value from the block-based NSNotificationCenter method, etc. Standard stuff. The only thing that surprised me was the reference cycle in NSAssert. Then again, given Apple's poor regard for TDD, that shouldn't surprise me.
Re: NSNotificationCenter with blocks considered harmful
#6If you over-do it then NSNotifications easily can become distributed goto. Once I had to add features to a Mac application that made heavy (ab)use of NSNotifications. Following code paths was a nightmare.
I tend to prefer the delegate pattern because there the relationships between objects are clear. Even if it means more work (creating glue code) - your sanity is worth it.
Re: NSNotificationCenter with blocks considered harmful
#7Just a heads up though: The code snippet were hard to read because of the indentation. May I suggest
cleanupObj = [[NSNotificationCenter defaultCenter]
addObserverForName:notificationName
object:nil
queue:nil
usingBlock:^(NSNotification *note) {
// Code!
}];
It might not be your coding style but in very narrow container, it makes it easier to read ;)Re: NSNotificationCenter with blocks considered harmful
#8This really applies equally to any block that captures self. Blocks are, IMHO, the one place where ARC really falls down versus garbage-collection.
Yes, it's just a retain cycle. Self retains block, block retains self. The only thing that makes this case confusing is that self only holds the block implicitly (via the notification center instead of any obvious ivar). Otherwise it's a design pattern that every reference counted language user must understand to avoid memory leaks. Weak references to self in blocks are a very common design pattern that all Objective…
If you access an instance variable by reference, a strong reference is made to self;
If you access an instance variable by value, a strong reference is made to the variable."
Right. So if you use self or an instance variable, you've just created a strong reference. In Drew's example, as he is relying on the object going out of scope, that will still leave the reference held by the block, which is itself held by the NotificationCenter. As with all reference cycles, the way out is to get the NotificationCenter to stop observing that notification, or as the Apple documentation says, use a local variable that takes the value of self, and use that local variable inside the block. This is the solution that Drew presents as Attempt6, but quite frankly would have been my very first attempt when the test failed. The stuff about __block is a red-herring, and from the documentation goes in the opposite direction that Drew wants, forcing a strong reference rather than removing it.Drew also gets bitten by NSAssert using self. I would suggest that it is NSAssert that is doing something dodgy here - it's trying to have an implicit self, as though it was a method, when it most definately isn't a method - and Drew just got bitten by the impedence mismatch. Macros - just say no.
Re: NSNotificationCenter with blocks considered harmful
#9There's nothing really magical about this – don't cause retain cycles, everyone knows __block semantics changed with ARC, keep the returned value from the block-based NSNotificationCenter method, etc. Standard stuff. The only thing that surprised me was the reference cycle in NSAssert. Then again, given Apple's poor regard for TDD, that shouldn't surprise me.
By the way, you can prevent the retain cycle in NSAssert using libextobjc's @weakify and @strongify macros.
libextobj is great.