Comments on: NSNotificationCenter with blocks considered harmful /code/nsnotificationcenter-with-blocks-considered-harmful/ sealed abstract class drew {} Sun, 27 Mar 2016 22:51:38 +0000 hourly 1 https://wordpress.org/?v=4.4.15 By: Nik /code/nsnotificationcenter-with-blocks-considered-harmful/comment-page-1/#comment-974006 Sun, 27 Mar 2016 22:51:38 +0000 /?p=2071#comment-974006 Thanks for the warning… and using blocks may be a bad idea in this case.

However, I have to dismiss a large part of the article simply due to the fact that you don’t remove observers in dealloc.

That’s a no-no. Why IN THE WORLD would you rely on an object being deallocated to do that? You want to have some reliably in and out for adding/removing observers – viewWillAppear and viewWillDisappear for example, or if it’s a non-view object, then add an observer once and just keep it around forever or as long as your object is around.

Introducing a dependency on an object being collected is basically hard-wiring your logic to the entire rest of the program. Who knows what will be – legitimately – holding on to that object? Who can predict?

Relying on dealloc is basically the equivalent of a goto: statement, or relying on a global variable. Don’t do it.

cheers thanks 😉

]]>
By: Aapo Kuuselo /code/nsnotificationcenter-with-blocks-considered-harmful/comment-page-1/#comment-11440 Tue, 10 Dec 2013 00:45:23 +0000 /?p=2071#comment-11440 “On line 89 of AVCamCaptureManager.m, Apple uses the syntax __block id weakSelf = self;, apparently under the impression that this breaks the reference cycle. No instance of this class can ever be deallocated. A GitHub search reveals some 77 repositories contain some version of this class.”

Yeah, I’ve noticed!

Had to go into my code base and dig this one up. I added this kind of hacky piece of code and call it manually to make the damned AVCamCaptureManager dealloc:

(void) removeLeakyObservers
{
NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter];
[notificationCenter removeObserver:[self deviceConnectedObserver]];
[notificationCenter removeObserver:[self deviceDisconnectedObserver]];
}

And thanks for this dive into the (at least for me) good old weakSelf & strongSelf dance that came as a little nasty side effect of ARC’s new way of handling variables defined as __block. Though the ARC documentation does describe (with examples) this well, it is a nasty little change in the way things worked earlier.

]]>
By: Joachim Bengtsson /code/nsnotificationcenter-with-blocks-considered-harmful/comment-page-1/#comment-11232 Wed, 20 Nov 2013 07:46:56 +0000 /?p=2071#comment-11232

I wonder why LLVM automatically create weak references to ‘self’ within a block by default. Not sure if it is too difficult for LLVM folks to bring it in.

Because that would be at least as wrong. All Objective-C object references are captured strongly, that’s the API contract. If self was special cased to be weak, this would break:

[[thing sendRequest:r withCallback:^(id value) {
[self parseValue:value];
  [self save];
}];

Since self is captured strongly, we’re guaranteed to live at least as long as this request, even if all other references to the self object have been released except this block, so that we can definitely handle the response unless the request is explicitly cancelled.

Special casing self to be weak wouldn’t help in this situation, either:

id manager = …;
[manager onFailure:^{
[manager cleanup];
}];

Retain cycle!

So maybe we can go so far as to say all objc values should be captured weakly?

NSArray *array = @[@1];
[thing sendRequest:r withCallback:^(id response){
[response doSomethingWithNonNilObject:array];
}];

Nope, crash.

So, the current behavior of strong capture of every Objective-C object is the sanest solution, but is problematic since we don’t have garbage collection to take care of cycles. Harsh life as a programmer. We have to learn our tools very thoroughly and learn how to handle these cases correctly instead. ARC made life easier but it’s not a panacea.

]]>
By: Aaron Daub /code/nsnotificationcenter-with-blocks-considered-harmful/comment-page-1/#comment-11231 Wed, 20 Nov 2013 07:43:11 +0000 /?p=2071#comment-11231 It looks like you can -> down to private/protected ivars but Xcode doesn’t like it when you dereference a weak pointer with ->.

You have to create a strong variable within the block that’s a copy of the weak reference, and dereference that.

]]>
By: Joachim Bengtsson /code/nsnotificationcenter-with-blocks-considered-harmful/comment-page-1/#comment-11230 Wed, 20 Nov 2013 07:17:50 +0000 /?p=2071#comment-11230 Aaron: Actually you can’t, because you can’t dereference a weak pointer (it might become nil at any point, so it’s always unsafe to dereference it). However, inside the block you can create a strong reference, and dereference THAT one only if it is not nil.

__weak __typeof(self) weakSelf = self;
[something doSomething:^{
__strong __typeof(weakSelf) strongSelf = weakSelf;
if(strongSelf)
strongSelf->_ivar++;
}];

Also, this whole blog article is rather over the top. Yes, memory management in blocks is difficult. That’s the price to pay for not having a garbage collector. That doesn’t mean you can just ignore the rules, and it doesn’t mean that block-using APIs are bad. It just means you don’t know how to use blocks. (and I know you don’t know how to use block because you made an instance variable __block. That doesn’t even mean anything. And you didn’t do what the documentation said — it implied that you should’ve made the reference to self weak, not the reference to the ivar.)

It’s also worth to note that if you don’t unregister from notifications with the target-action API, you’ll crash. There’s plenty of code using that API incorrectly too, and that’s just as bad.

]]>
By: Drew Crawford /code/nsnotificationcenter-with-blocks-considered-harmful/comment-page-1/#comment-11229 Wed, 20 Nov 2013 07:00:12 +0000 /?p=2071#comment-11229 You can only deref with the arrow operator if the ivar is declared @public.

]]>
By: Aaron Sarazan /code/nsnotificationcenter-with-blocks-considered-harmful/comment-page-1/#comment-11228 Wed, 20 Nov 2013 06:59:21 +0000 /?p=2071#comment-11228 Fyi, you don’t have to maintain a public interface to access that variable in mySelf. You can just deref it with the arrow operator as such: mySelf->_localCounter++;

The rest of this is terrifying.

]]>
By: Shripada /code/nsnotificationcenter-with-blocks-considered-harmful/comment-page-1/#comment-11227 Wed, 20 Nov 2013 06:17:22 +0000 /?p=2071#comment-11227 Nice article!. Retain cycle with blocks is a subtle trap to figure out and fix and this NSNotificationCenter API takes it to new heights!. I wonder why LLVM automatically create weak references to ‘self’ within a block by default. Not sure if it is too difficult for LLVM folks to bring it in.

Thanks
Shripada

]]>
By: Mark Lilback /code/nsnotificationcenter-with-blocks-considered-harmful/comment-page-1/#comment-11226 Wed, 20 Nov 2013 06:12:29 +0000 /?p=2071#comment-11226 The use of __weak is documented in Apple’s “Transitioning to ARC Release Notes” and has been since ARC was first released. There are lots of easy to understand examples. That was fine when ARC came out, but they really should have copied or linked to that from somewhere else.

Since I first started iOS programming, I’ve been using ZAssert
http://www.cimgf.com/2010/05/02/my-current-prefix-pch-file/ by Marcus Zarra. It doesn’t reference self.

I would consider the real bug to be on NSAssert, which should not reference self. Or be documented to not be used in a block.

]]>
By: Marc /code/nsnotificationcenter-with-blocks-considered-harmful/comment-page-1/#comment-11225 Wed, 20 Nov 2013 04:59:12 +0000 /?p=2071#comment-11225 “AVCam – On line 89 of AVCamCaptureManager.m, Apple uses the syntax __block id weakSelf = self;, apparently under the impression that this breaks the reference cycle. No instance of this class can ever be deallocated. A GitHub search reveals some 77 repositories contain some version of this class”

If you do weakSelf = nil; inside the block after you are done it will break the retain cycle. You have to be careful if you use dispatch_asyncs that reference the weakSelf, make sure to nil it out inside the dispatch and not right after it.

Apple sample code is generally of low quality and should not be trusted.

Thank you for the warning about NSAssert, most of us did not see that one coming…

]]>