iOS 的strong和copy

作者: 后浪普拉斯 | 来源:发表于2018-04-27 17:24 被阅读4次

    之前有过一篇文章关于iOS 属性的 iOS指示符 assign、copy、retain、strong、weak,之后看了一遍有总结了一下:

    NSString 选 Strong 还是copy?

    1、现分别创建NSString 的strong 和 copy 两个属性

    
    @property(nonatomic, strong) NSString *age1;
    @property(nonatomic, copy) NSString *age2; 
    
    

    2、创建一个NSString 常量,赋值给上面的age1和age2两个属性。

        NSString *age = @"11";
        NSLog(@"age:  %@ - %p", age, age);
        self.age1 = age;
        self.age2 = age;
        NSLog(@"age1: %@ - %p", self.age1, self.age1);
        NSLog(@"age2: %@ - %p", self.age2, self.age2);
        
        NSString *ageOther = [age stringByAppendingString:@"20"];
        NSLog(@"age:  %@ - %p", age, age);
        NSLog(@"ageother:  %@ - %p", ageOther, ageOther);
        NSLog(@"age1: %@ - %p", self.age1, self.age1);
        NSLog(@"age2: %@ - %p", self.age2, self.age2);
    

    3、结果:

     age:  11 - 0x108f28078              
     age1: 11 - 0x108f28078              
     age2: 11 - 0x108f28078              
     age:  11 - 0x108f28078              
     ageother:  1120 - 0x600000255000    
     age1: 11 - 0x108f28078              
     age2: 11 - 0x108f28078              
    

    分析:
    我们可以发现,给age1和age2 赋值一个不可变的字符串的时候,都进行了浅拷贝,只拷贝了指针地址,使age、age1、age2都指向同一个地址,在对age进行增加字符串时,因为age是不可变字符串,所以age没有变化,于是age1、age2都没有变化。

    总结:声明String和copy属性的String被不可变String赋值时,没有变化,都是浅拷贝,都不会发生变化。

    1、现分别创建NSString 的strong 和 copy 两个属性

    
    @property(nonatomic, strong) NSString *str1;
    @property(nonatomic, copy) NSString *str2;
    
    

    2、创建一个NSMutableString 可变字符串,赋值给上面的str1和str2两个属性。

        NSMutableString *name = [[NSMutableString alloc] initWithString:@"Alex"];
        NSLog(@"name : %@ - %p", name, name);
        self.str1 = name;
        self.str2 = name;
        NSLog(@"str1 %@ - %p", self.str1, self.str1);
        NSLog(@"str2 %@ - %p", self.str2, self.str2);
        
        [name appendString:@"Le"];
        
        NSLog(@"str1 %@ - %p", self.str1, self.str1);
        NSLog(@"str2 %@ - %p", self.str2, self.str2);
    

    3、结果:

     name : Alex - 0x604000255cc0       
     str1 : Alex - 0x604000255cc0       
     str2 : Alex - 0xa00000078656c414   
    
     str1 : AlexLe - 0x604000255cc0     
     str2 : Alex - 0xa00000078656c414              
    

    分析:
    我们可以看出在用可变字符串给属性变量赋值时,strong的str1 对name进行浅拷贝,只拷贝了地址,所以str1和name指向同一个地址,而copy 的 str2 对name 进行了深拷贝,str2将name复制到一个新空间内。
    当我们对name增添时,此时我们可以看到和name指向相同的str1的内容改变了,而新开辟空间的str2却还保持原来的值。

    总结:

    声明String和copy属性的String被可变的NSMutableString name赋值时,strong类型的会随可变字符串的变化而变化,但是copy类型的却不会随可变字符串的变化而变化。所以当属性被不可变的字符串赋值时,strong和copy没有区别;当属性被可变字符串赋值时,copy不会被修改,而strong会被修改。综上所述,copy更简单、安全。

    NSArray 和 NSMutableArray 是 copy 还是 strong?

    1、NSMutableArray 不能被copy修饰,因为以后对数组的增删改操作在copy之后数组都会变成不可变数组,对其进行增删改都将crash。

          @property (copy) NSMutableArray * a;
          NSMutableArray* b = [NSMutableArray array];
          a = b;
    

    等同于

           @property (strong) NSMutableArray * a;
           NSMutableArray* b = [NSMutableArray array];
           a = [b copy];
    

    a在被copy之后就变成了不可变数组NSArray了。

    2、NSMutableArray 被strong修饰,在赋值的时候就如上面说的那样会指向同一个地址,被定义的属性也不会改变。

    @property(nonatomic, strong) NSMutableArray *arrayA;
    @property(nonatomic, copy) NSMutableArray *arrayB;
    
        NSMutableArray *arrayC = [NSMutableArray array];
        NSLog(@"arrayC.class: %@ - %p", arrayC.class, arrayC);
        self.arrayA = arrayC;
        self.arrayB = arrayC;
        NSLog(@"arrayA.class: %@ - %p", _arrayA.class, _arrayA);
        NSLog(@"arrayB.class: %@ - %p", _arrayB.class, _arrayB);
        
        [self.arrayA removeAllObjects];
        [self.arrayB removeAllObjects];
    

    结果:

    arrayC.class: __NSArrayM - 0x604000251220                                                                                                                                   
    arrayA.class: __NSArrayM - 0x604000251220                                                                                                                                   
    arrayB.class: __NSArray0 - 0x6000000021a0                                                                                                                                   
    -[__NSArray0 removeAllObjects]: unrecognized selector sent to instance 0x6000000021a0                                                                                       
    *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSArray0 removeAllObjects]: unrecognized selector sent to instance 0x6000000021a0' 
    

    分析:我们可以看到arrayA 和 arrayC的指向同一个地址,且类型都是mutable的,arrayB的类型发生了改变变成不可变的类型。所以,NSMutableArray被copy修饰之后就变成不可变的,在对其操作时容易crash。
    而NSArray被copy或者strong修饰的时候和NSString相同。

    1、当arrayA被strong修饰,且被可变数组赋值,可变数组arrayMB改变,被strong修饰属性arrayA也做同样修改,arrayA和arrayMB指向的地址相同;
    2、当array被copy修饰,且被可变数组赋值,可变数组arrayMB改变,被copy修饰的属性arrayB没有被修改,因为arrayB深拷贝arrayMB,arrayB和arrayMB在两个内存块中。
    3、不管array被strong、copy修饰,只要被不可变数组赋值,此时都指向同一个内存地址。

    NSMutable可变的类型最好不要使用copy,不可变的看需不需要被修改,在看strong 和 copy的定义。

    相关文章

      网友评论

        本文标题:iOS 的strong和copy

        本文链接:https://www.haomeiwen.com/subject/hhiblftx.html