Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What's the equivalent of '[[something retain] autorelease]' in ARC?

What's the equivalent of [[something retain] autorelease] in ARC?

I have a problem where a class DBRequest calls my delegate to signify completion. My delegate then sets the DBRequest instance to nil, which dealloc's it. But then when the stack pops out of my delegate and jumps back to the DBRequest, it of course then crashes.

If I wasn't in ARC, in my delegate I'd simply do [[theDbRequest retain] autorelease] before releasing my reference to it, so that it'd survive long enough until the next run loop autoreleased it.

What should I do in ARC?

like image 622
Chris Avatar asked Mar 10 '12 03:03

Chris


3 Answers

How about adding something like

__strong DBRequest * myself = self;
[delegate reportDone];

I think that'll increment the self object until the end of the function preventing it from dying early.

like image 133
Winston Ewert Avatar answered Nov 12 '22 09:11

Winston Ewert


My delegate then sets the DBRequest instance to nil, which dealloc's it. But then when the stack pops out of my delegate and jumps back to the DBRequest, it of course then crashes.

Surely this was always a bad strategy, and your [[theDbRequest retain] autorelease] was always just covering up the problem, yes?

Simply do nothing. So your instance variable sticks around; so what? You know that ARC will release it for you when you are dealloced.

The important thing is not to release theDbRequest, but to set theDbRequest's reference to you (the delegate) to nil, so it doesn't try to call you back when you no longer exist. Your own dealloc would be a good place to do that.

Hope I'm understanding the issue correctly. If not, post some code!

like image 26
matt Avatar answered Nov 12 '22 09:11

matt


As @matt says if you simply do nothing ARC should clean up when your object is deallocated - assigning the DBRequest you create to an instance variable handles that (provided of course your object outlasts the object you are creating).

If you need to deallocate the DBRequest before your object dies then you need an ARC-compatible "trick" equivalent to [[theDbRequest retain] autorelease]. Now unless you are constructing your own auto release pools your previous approach would trigger at the end of the current event. Following that logic try:

  1. Add a method to your class which simply sets theDbRequest to nil, let's call this cleanUpTheDbRequest.
  2. Change your delegate callback to invoke [self performSelectorOnMainThread:@selector(cleanUpTheDbRequest) withObject:nil waitUntilDone:NO] instead of directly assigning nil to theDbRequest

This should delay the assigning of nil till after the end of the current event, just as your autorelease "trick" did. It also works if your DBRequest lives across multiple events - the previous method kicks in at the end of the event the autorelease is called in, this method at the end of the event the delegate method is called in.

like image 3
CRD Avatar answered Nov 12 '22 09:11

CRD