1

Sorry if this is an duplicated entry, I am new to OC.
I have turned off "Object-C Automatic reference counting" in build settings. And I have two classes Guitar and GuitarController.
GuitarController.m looks like this:

#import "GuitarController.h"

@implementation GuitarController

-(void) setGuitar:(Guitar*) newGuitar
{
    guitar = newGuitar; 
    // Yes, i did not retain the guitar object. 
    // I did it on purpose to test whether something will go wrong
}

-(void) playGuitar
{
    [guitar play];
}
@end

and Guitar.m looks like this:

#import "Guitar.h"

@implementation Guitar
-(void) play
{
    NSLog(@"play guitar!!!");
}
@end

finally, the main.m code:

#import <Foundation/Foundation.h>
#import "GuitarController.h"

int main(int argc, const char * argv[])
{
    Guitar* guitar = [[Guitar alloc] init];
    GuitarController* guitarController = [[GuitarController alloc] init];
    [guitarController setGuitar:guitar];
    [guitar release]; 
    [guitarController playGuitar]; // Expecting an error here
    return 0;
}

The code above works just fine. But it is obviously wrong because I referenced an Object after its reference count became 0. Any clues? Thanks!

John Wu
  • 1,015
  • 1
  • 12
  • 21

1 Answers1

3

It's very likely that the guitar has not been returned to the OS yet. That's very normal. Real memory allocations are expensive. Cocoa avoids them when it can. For such a tiny object, Cocoa almost certainly just stuck it in its private pool to allocate again later. That means your application still technically owns the memory, so accessing it is totally legal, and you won't get an exception. See A look at how malloc works on the Mac for more details on that.

Accessing memory after you've released it is undefined behavior. You cannot "expect" anything after you do that. The computer can catch on fire, and that would be considered in spec. The program can also continue to work perfectly. That would also be in spec. The system makes you no promise that you will receive an error.

I hope that you have turned off ARC simply to try to learn a little more about the underlying system. If so, that's fine. But for any serious program you should turn on ARC.

Community
  • 1
  • 1
Rob Napier
  • 286,113
  • 34
  • 456
  • 610
  • `NSZombies` should help here, I think. – Léo Natan Dec 22 '13 at 04:25
  • @LeoNatan, yes, if you were debugging this issue, NSZombies would often be a useful tool. But the static analyzer would be a better one. This kind of trivial mistake should be caught easily. (Of course, when you turn ARC back on, the mistake is impossible.) – Rob Napier Dec 22 '13 at 04:27
  • Does the static analyzer go deep into the setter method, including analyzing possible side effects? I must admit, I have used the analyzer before, but have not seen any errors in such cases, so I am not aware of its capabilities. It is great with CF/CG stuff, though. – Léo Natan Dec 22 '13 at 04:35
  • Sorry; no it can't get that deep. I was thinking the access was to guitar rather than guitarController. As you say, the static analyzer won't find this one since the mistake is in the setter, not in the caller. – Rob Napier Dec 22 '13 at 04:43
  • 1
    Having said that, this does not diminish the value of the static analyzer. It is invaluable for manual retain and release code, just as it is for CF/CG stuff (even more so, I might argue). If you're not going to use ARC, then you really should use the static analyzer liberally. – Rob Dec 22 '13 at 04:50
  • Thanks for your help. And, yes, I turned off ARC just for inspecting inside to see how things work :) Thanks guys! – John Wu Dec 22 '13 at 11:46