2
votes

I tend to regularly use self.property in my Objective C code when accessing variables as I understand that this makes use of the getter/setter methods (either explicitly coded or automatically generated).

Another coder told me recently that it's best to use _property instead, throughout the code. But my understanding is that _property is really only for use in init and dealloc methods.

Today I found a bug in some code that uses initWithCoder. I was using _property in the initWithCoder method and had to change it to self.property. This was when setting an NSData object. Here is the original code:

@property (nonatomic, strong) NSData *data;

- (id)initWithCoder:(NSCoder *)decoder {
    self = [super init];
    if (!self) {
        return nil;
    }
    _data = [decoder decodeObjectForKey:@"data"];
    return self;
}

And I had to change it to this, to get it to work:

@property (nonatomic, strong) NSData *data;

- (id)initWithCoder:(NSCoder *)decoder {
    self = [super init];
    if (!self) {
        return nil;
    }
    self.data = [decoder decodeObjectForKey:@"data"];
    return self;
}

My question is - why is initWithCoder the exception here? If it's generally accepted that it's best to use _property in an init method, then why is initWithCoder different?

It seems now like the general rule is:

Use self.property except in init/dealloc methods, where _property should be used (except in initWithCoder, where self.property should be used).

Is this correct?

1
I cant see a reason why in initWithCoder: your code self.property would work when _property wouldn't. You got it correct that self.property uses the setter of this property to initialize it, whereas _property doesn't take the detour through the setter but rather initializes the instance variable that belongs to your property directly... This seems strange :/nburk
When you say "to get it to work," what bug did you encounter. I don't see a problem with the original ivar-based init. The coder who told you to use ivars exclusively is incorrect; that is not best practice. There was a time when there was more disagreement within the ObjC community, but Apple has finally documented that you should use the accessors except in init and dealloc.Rob Napier
I just made a test, it works with both _data and self.data. What version of iOS are you targeting? much earlier versions would not auto-generate the _data variable for the property data.Daniel
The error occurs when returning from initWithCoder, not while in initWithCoder. I put a breakpoint in initWithCoder and the assignment to _data was okay. The problem occurs just after the [NSKeyedUnarchiver unarchiveObjectWithFile:cachePathForKey]; statement. When it returns from this, the object contains garbage, unless I use self.data instead of _dataDarren
The deployment target for the app is 7.0Darren

1 Answers

1
votes

I do not think it is generally true that you must use properties in initWithCoder:. I have a lot of code (and have seen a lot) where ivar access is used in initWithCoder:, if that may help as a hint.

If you were not using ARC, then your implementation setting _data would have a problem in that the object would be soon autorelased. But under ARC your code is correct.

So, I tend to think that something different was causing the issue in your case. As an example, if you use KVO, then you should use properties, otherwise the KVO-related notifications are not generated. You should provide more information as to what exactly led you to think that the assignment to _data was the cause of the issue, and about the visible effect of that issue in other parts of your code.