4

Out of curiosity/excitement I have been reading whatever information I can find about ARC but I have one question I can't seem to find the answer to. Not sure if people can answer this due to NDAs or whatever, but I'll ask anyway. (There's plenty of information out there.......)

One thing ARC advertises is that you won't need to write dealloc methods anymore. Cool. But is this really true?

If I have a NSNetService or something, normally in my dealloc I would write

- (void)dealloc
{
    [netService_ setDelegate:nil];
    [netService_ stop];
    [netService_ release];

    [super dealloc];
}

Does ARC take care of that now? Or is not smart enough to know about stuff like that? If it isn't smart enough to know about that stuff (meaning I would still have to write custom deallocs in certain cases) would I have to release all ivars? Or just ones that wouldn't be simple releases?

- (void)dealloc
{
    [netService_ setDelegate:nil]; // if these 3 lines are necessary...
    [netService_ stop];
    [netService_ release];

    [myString_ release]; // would this one still be? or would ARC know to automagically add this
    [super dealloc]; // seems this is forbidden in ARC
}

I guess my question really boils down to this: ARC says you won't have to write deallocs anymore in most cases; so when are the cases you do have to?

Halnry
  • 418
  • 2
  • 10
  • Whenever you do write your own dealloc, don't forget to call [super dealloc] (as you have in your sample code) – Danra Oct 10 '11 at 20:50
  • Thanks. I'll edit. I left it out because I believe it's an error to call that when ARC is enabled. – Halnry Oct 10 '11 at 21:01
  • 2
    @Danra, you don't call `[super dealloc]` under ARC. – Jim Oct 18 '11 at 13:42

3 Answers3

4

As far as I understand it, you should think of ARC as just the static-analyzer built into the compiler, synthesizing retain and release calls where required (Which is also the reason why ARC code will be backwards-compliant with devices running iOS4).

So there is no way netService_ in your sample will be stopped automatically. You will need to write your own dealloc in this case.

The delegate issue is interesting, in iOS5 lingo it will be a weak property so it might be set to nil on dealloc... Not sure but it's interesting!

Another case you will have to take of yourself is you have handle objects which aren't objective-c objects, for example for Core Foundation objects you will need to write CFRetains and CFReleases yourself.

Danra
  • 9,546
  • 5
  • 59
  • 117
  • Ahh yes, I remember reading about those zeroing weak properties now... you're right that should theoretically handle itself. I guess you can't rely on every class having there delegate as a weak property though? – Halnry Oct 10 '11 at 21:04
  • Every well written class should have its delegate as a weak/assign property. See also this: http://stackoverflow.com/questions/7246513/zeroing-weak-references-in-arc – Danra Oct 10 '11 at 21:40
2

I think that if there is anything you need to do to cleanup an object, other than releasing it, is fair game for a custom dealloc method.

So in your own example with netService_, the calls to setDelegate: and stop would be reasonable to call, but there'd be no need to call release because ARC takes care of that.

Mark Granoff
  • 16,878
  • 2
  • 59
  • 61
  • That's great if that's how it truly is. Seems reasonable. – Halnry Oct 10 '11 at 20:58
  • The `setDelegate:` call should be unnecessary, assuming that it's properly set up as a zeroing weak reference. @user988375 – jscs Oct 10 '11 at 21:03
  • @JoshCaswell what if the delegate (or another object) were a `strong` reference? Then you'd need to set it to `nil` in the dealloc? – Dan Rosenstark Oct 18 '11 at 05:23
  • @Yar: Yes, if the object of which this being-deallocated object is the delegate was expected to live on. – jscs Oct 18 '11 at 07:58
  • @JoshCaswell Just ran a small test, apparently ARC will set strong properties to nil when an object is dealloc'ed. Interesting. Wrote answer below. – Dan Rosenstark Oct 18 '11 at 13:35
0

It's clear that ARC wouldn't know about your [netService_ stop]; line. You'd have to include that yourself, since it's non-standard and does not have to do with retain/release.

Right after your dealloc is run, ARC will release all strong and weak properties (and __strong and __weak iVars).

Here's some test code, just to see what happens:

@interface TestClass : NSObject

@property (nonatomic, strong) TestClass *anotherTestObject;

@end


@implementation TestClass
@synthesize anotherTestObject;

- (void)dealloc {
    NSLog(@"I am deallocing %d", self.hash);
}

@end

And my test:

TestClass *thing1 = [[TestClass alloc] init];
NSLog(@"thing 1 %d", thing1.hash);

thing1.anotherTestObject = [[TestClass alloc] init];
NSLog(@"thing 2 %d", thing1.anotherTestObject.hash);

This will print out something like this

thing 1 1450176
thing 2 1459984
I am deallocing 1450176
I am deallocing 1459984

Since only one of the objects is getting autoreleased (thing1) at the end of the test code, you can immediately tell that thing2 is getting released by someone else (since it's in a strong property). However, if you overwrite setAnotherTestObject you find that ARC is not setting it to nil but rather just releasing it directly. You cannot override release in ARC, otherwise I could demonstrate this too ;)

If I adjust the code and use weak instead of strong, the same behavior persists, but the output is different since the test case isn't holding onto the weak reference whatsoever.

Dan Rosenstark
  • 68,471
  • 58
  • 283
  • 421