Best practice for copying private instance vars with NSCopying
Asked Answered
S

3

10

I might be missing something obvious here, but I'm implementing NSCopying on one of my objects. That object has private instance variables that are not exposed via getters, as they shouldn't be used outside the object.

In my implementation of copyWithZone:, I need alloc/init the new instance, but also set up its state to match the current instance. I can obviously access current private state from inside copyWithZone:, but I can't set it into the new object, because there are no accessors for that state.

Is there a standard way around this while still keeping data privacy intact?

Thanks.

Salamanca answered 2/4, 2010 at 15:10 Comment(0)
T
8

First, you should always have getters, even if they're private. Your object should only access even its own ivars using accessors (except in a very small number of cases). This will save you a great deal of suffering over memory management.

Second, Alex's suggestion of using -> is a standard approach, even though this violates the getters rule above. There are a small number of exceptions to that rule, and copy is one of. Using private setters here is still reasonable (and I used to do it that way exclusively), but I've found for various reasons that using -> often works out cleaner.

Be very careful to get your memory management correct. If you need to call [super copyWithZone:], then you should also read up on the complexities of NSCopyObject() and how it impacts you even if you don't use it yourself. I've discussed this at length in "NSCopyObject() considered harmful."

Tome answered 2/4, 2010 at 15:31 Comment(3)
Thanks for the mention of private accessors as well as the perils of NSCopyObject.Salamanca
I am not sure how does having readonly accessors help memory management? If you are not using it with assign or retain, it makes no difference whether you use getter or the variable directly.Stitching
@Hemant, Because the caller should not need to be careful about whether the property is currently (or in the future) readonly or not. That is not the caller's business, and it could change over time, and then you would need to hunt down every piece of code that did it incorrectly. By sticking to simple rules, errors become obvious. When you say "oh, except when I happen to know that it's currently ok" then you're opening yourself up for maintenance headaches.Tome
J
5

You can access the instance variables of the copy directly. You use the same pointer dereferencing syntax you would use with a struct. So, for example, if your class is this:

@interface MyCopyableClass : NSObject {
    int anInstanceVariable;
}
@end

You can do this:

- (id)copyWithZone:(NSZone *)zone {
    MyCopyableClass *theCopy = [[[self class] allocWithZone:zone] init];
    theCopy->anInstanceVariable = anInstanceVariable;
    return theCopy;
}
Johnnajohnnie answered 2/4, 2010 at 15:22 Comment(0)
J
1

One option is to create a custom initializer that accepts the private iVar values. So you create it like:

-(id) initWithPropertyOne:(SomeClass *) anObject andPropertyTwo:(SomeClass *) anotherObject;

When you instantiate the copy, just use the custom initializer.

Julee answered 2/4, 2010 at 15:32 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.