Suppose that I have a class that holds a mutable array. I want to make sure that if other classes ask for the array they will get a non-mutable type, but in the owning class, it is actually an instance of NSMutableArray
, so that I can add and remove items.
#import "Person.h"
@class Asset;
@interface Employee : Person
{
NSMutableArray *_assets;
}
@property (nonatomic,copy) NSArray *assets;
-(void)addAssets:(Asset *)a;
The question is, do I have to modify the accessor methods into something like this, or will it automatically behave like I want?
#import "Employee.h"
#import "Asset.h"
@implementation Employee
/* Accessors for assets properties
-(NSArray *)assets
{
return [_assets copy];
}
-(void)setAssets:(NSArray *)assets
{
_assets = [assets mutableCopy ];
}
*/
-(void)addAssets:(Asset *)a
{
//is assets nil?
if (!_assets) {
//Create Array
_assets = [[NSMutableArray alloc]init];
}
[_assets addObject:a];
}
ppalancica's answer is incorrect. The copy
attribute means only that the setter will take a copy when the property is set. The synthesized getter will not return a copy. You must implement that behavior yourself:
- (NSArray *)assets
{
return [_assets copy];
}
You might want to make an internal-only accessor that doesn't make a copy. You could also redeclare the property privately; client code will then be contracted to treat the array it requests as immutable.
This code demonstrates that the synthesized getter returns the uncopied object:
#import <Foundation/Foundation.h>
@interface ArrayReturner : NSObject
@property (copy, nonatomic) NSArray * array;
@end
@implementation ArrayReturner
{
NSMutableArray * _array;
}
- (BOOL)myArrayIsIdenticalTo:(NSArray *)otherArray
{
return _array == otherArray;
}
@end
int main(int argc, const char *argv[])
{
@autoreleasepool {
ArrayReturner * a = [ArrayReturner new];
[a setArray:@[@1, @2]];
NSArray * returnedArray = [a array];
// Does not throw
NSCAssert([a myArrayIsIdenticalTo:returnedArray],
@"Returned array is a separate instance.");
}
return 0;
}