In ObjectiveC, is it necessary to declare a strong copy vs for the readonly property?
In Objective-C, it is common to declare an NSString / NSArray / NSDictionary as a copy, does this need to be done for the readonly property or is there no difference? If the NSString is read-only, it will never be set, so declaring it strong or a copy will have the same effect?
// use a strong copy here and it will work the same since it will never be copied?
@property (non-atomic, read-only) NSString * string;
source to share
You are correct, but there are some things to consider. This is good since your property is an immutable object. However, this is not always the case.
The first example I come across a lot is when you have an actually mutable object inside your implementation. As a property, the declared NSArray in the implementation can actually be an NSMutableArray. The strong reference getter property for it will return a pointer to this NSMutableArray. And at some point you will run into a situation when you request an NSArray from an object, work with it for a while and, boom !!! - does your NSArray have different elements of its quantity? What the heck? In this case it is better idea to copy your internal implementation used by NSMutableArray in getter.
Another example is some model object
@interface Person : NSObject <NSCopying>
@property NSString *name;
@property NSDate *birthdate;
@end
And you have another interface with the property
@property (strong, readonly) Person *person;
Yes, you will not assign another object to this property. However, you will be able to change your fields, so it will represent a completely different face. If you don't want this behavior, make this property copy
. Or make it private with accessor methods to get its fields
- (id) getHiddenPersonPropertyValueForKey:(NSString *)personPropertyKey;
Or in any other way
source to share
If the property represents a truly immutable value ( NSArray
, NSIndexSet
etc.), then just readonly
fine, since it will be returned immutable as is.
But in case your private ivar is mutable ( NSMutableArray
ivar vs property NSArray
type), you must return a copy to prevent future internal changes from leaking to the caller state.
@interface MyObject : NSObject {
NSMutableArray *_array;
}
@property(nonatomic, readonly) NSArray *array;
// -or-
- (NSArray *)array;
@end
and
@implementation
@dynamic array; // only if @property was declared in interface
- (NSArray *)array
{
return [_array copy];
}
@end
The caller then stores the value of the property and expects it not to change even without an explicit copy:
self.array = [myObject array]; // e.g. 1 element
[myObject addElementToArray:@(42)];
NSLog(@"%@", self.array); // still 1 element
source to share