Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Should I use copy or strong with arrays?

I am talking about ARC projects.

I have always declared array properties like this

@property (strong, nonatomic) NSArray *myArray;

but I have seen a lot of people recommending using this:

@property (copy, nonatomic) NSArray *myArray;

People suggesting copy say "The copy on myArray is to prevent modification by another "owner" of the object you set." This "explanation" sounds klingon to me.

Can someone explain the meaning of this as I am 5 years old? OK, make it 3.

thanks

like image 652
Duck Avatar asked Nov 18 '14 11:11

Duck


4 Answers

Copy is shallow, it only copies the pointer. If the array contains a mutable object and that object is changed the change will appear in the copied array.

NSMutableString *s = [@"test1" mutableCopy];
NSArray *a1 = @[s];
NSArray *a2 = [a1 copy];
NSLog(@"\na1: %1$p, %1$@\na2: %2$p, %2$@", a1, a2);
[s appendString:@"2"];
NSLog(@"\na1: %1$p, %1$@\na2: %2$p, %2$@", a1, a2);     

Output:

a1: 0x10010fed0, (
    test1
)
a2: 0x10010fed0, (
    test1
)

a1: 0x10010fed0, (
    test12
)
a2: 0x10010fed0, (
    test12
)

The reason for the copy is for protection in the case where the array being copied is a mutable array so that any change of the original array will not change the copied array. The difference is a change in the mutable array and a change in an object in the mutable array. Note, the further reason is that one may not know that the array being assigned is mutable or not.

NSString *s1 = @"test1";
NSString *s2 = @"test2";
NSMutableArray *a1 = [@[s1] mutableCopy];
NSArray *a2 = [a1 copy];
NSLog(@"\na1: %1$p, %1$@\na2: %2$p, %2$@", a1, a2);
[a1 addObject:s2];
NSLog(@"\na1: %1$p, %1$@\na2: %2$p, %2$@", a1, a2);

Output:

a1: 0x100200510, (
    test1
)
a2: 0x100200650, (
    test1
)

a1: 0x100200510, (
    test1,
    test2
)
a2: 0x100200650, (
    test1
)

Note that copy on an immutable NSArray just performs an assignment so there is no cost. There is only a copy made when the array being assigned is an NSMutableArray.

NSString *s1 = @"test1";
NSString *s2 = @"test2";
NSArray *a1 = @[s1];
NSArray *a2 = [a1 copy];
NSLog(@"\na1: %1$p, %1$@\na2: %2$p, %2$@", a1, a2);

Output:

a1: 0x100300140, (
    test1
)
a2: 0x100300140, (
    test1
)
like image 75
zaph Avatar answered Oct 17 '22 02:10

zaph


The issue is that the array might mutate after setting the property, even though the property was defined as an immutable array. For example, consider,

NSMutableArray *array = [NSMutableArray arrayWithObjects:@1, @2, @3, nil];
obj.myArray = array;
[array addObject:@4];

If myArray was defined as strong, by changing the local mutable array would also change the myArray property of obj, too.

By defining myArray as copy, that ensures that you don't have to worry about the array itself mutating.

You still need to worry about the objects inside the array changing, and you might consider doing a deep copy if that's an issue, too.

like image 39
Rob Avatar answered Oct 17 '22 03:10

Rob


Its simple, Consider somewhere in your view controller

NSArray *myArrayCopy = self.myArray

Now If myArray is strong then if you change some object in myArrayCopy myArray will automatically changed. while in case of copy it would not changed as it will assign copy of myArray to myArrayCopy.

like image 1
Abhishek Avatar answered Oct 17 '22 02:10

Abhishek


It depends on whether you want to work on the same data or not. copy is indeed also "strong" so that the object will not be destroyed until the strong pointer is set to nil. But, strong references the same object while copy references a copy of the object. The generated setters would be something like:

-(void)setStrongArray:(NSArray*)data
{
   _strongArray = data;
}

-(void)setCopyArray:(NSArray*)data
{
   _strongArray = [data copy];
}
like image 1
Eike Avatar answered Oct 17 '22 03:10

Eike