Re: Fire-and-forget controllers with blocks
Re: Fire-and-forget controllers with blocks
- Subject: Re: Fire-and-forget controllers with blocks
- From: Ben <email@hidden>
- Date: Fri, 20 May 2011 17:23:29 +0100
On 20 May 2011, at 15:10, Dave Zarzycki wrote:
> On May 20, 2011, at 5:48 AM, Ben wrote:
>
>> MyImportController *controller = nil;
>> CleanupBlock cleanup = ^{
>> [controller release];
>> // Other stuff
>> };
>> controller = [[MyImportController alloc] initWithCleanupBlock:[[cleanup copy] autorelease]];
>> [controller start];
>> // The controller calls cleanup() when it's done
>>
>>
>> It doesn't exhibit any problems that I can see, but the static analyzer complains that I'm leaking the controller object in the second example. Am I actually doing something wrong here? If not, is there a way to make analyzer recognise this?
>
> Ben,
>
> The static analyzer is correct. The block captures the variable "controller" at the time of the block's creation, which in this case is nil, and sending messages to nil objects are for better and for worse allowed by the language.
>
> One could naively and wrongly "fix" this by decoupling the init method:
>
> controller = [[MyImportController alloc] init];
> // "controller" is now non-nil and safe to capture
> [controller setCleanupBlock: ^{ [controller release] }];
> [controller start];
>
> But because blocks automatically retain/release captured objects, the above code has actually just created a simple retain cycle and will never be freed (the controller retains the block and vice versa).
>
> In general, objects should not be responsible for their own cleanup. One might frequently get away with that in single-threaded code, but in concurrent code, that pattern is much more risky. Also, some of the memory analysis tools like "leaks" will get confused if a given object is the only reference to itself and will report these objects as leaks.
>
> There are other problems with this pattern too. If the controller has any accidental or intentional residual uses of itself after the cleanup handler runs, then things will blow up (a "use-after-free" bug).
>
> It would be hard at this point to give some good general advice without knowing more about what your design goals are.
>
> Good luck!
>
> davez
Thanks for the answer, that makes a lot of sense. Thanks also to Kyle's message afterwards.
To provide a bit more information, I have several parts of this app which need to display a sheet or series of sheets (eg. import, export, object creation). These are handled within their own window and/or view controller classes. All have a small amount or cleanup to perform after they are finished with, and must inform the parent document that they are done.
Basically, I thought I could take shortcuts using the cleanup blocks to avoid keeping references to the controller objects and to remove boilerplate -somethingDidEnd: methods from my code. The idea was for set-and-forget tasks which could clean up after themselves, since the UI they present is document-modal.
Thanks again for the advice, I will revert to the callback-based method now.
- Ben
_______________________________________________
Cocoa-dev mailing list (email@hidden)
Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden