What's the equivalent of '[[something reta

2019-04-28 15:09发布

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?

3条回答
beautiful°
2楼-- · 2019-04-28 16:02

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.

查看更多
叛逆
3楼-- · 2019-04-28 16:07

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!

查看更多
放我归山
4楼-- · 2019-04-28 16:07

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.

查看更多
登录 后发表回答