美文网首页
大话strong, copy和mutablecopy

大话strong, copy和mutablecopy

作者: 菜小狼 | 来源:发表于2016-08-23 19:09 被阅读0次

    1.strong和copy的区别

    通常情况下,我们在定义字符串属性的时候,会用到两种修饰词:strong和copy。但是比较规范的写法是用copy,也就是说copy要比strong更好,到底copy好在哪里?我们下面用实例来说明。

    @interface ViewController ()
    @property (nonatomic, copy) NSString* str1;
    @property (nonatomic, strong) NSString* str2;
    @end
    
    - (void)viewDidLoad {
        [super viewDidLoad];
        // Do any additional setup after loading the view, typically from a nib.
        NSMutableString* tempStr = [@"hello" mutableCopy];
        self.str1 = tempStr;
        self.str2 = tempStr;
        NSLog(@"str1 = %@, str2 = %@",self.str1, self.str2);
        [tempStr appendFormat:@"world"];
        NSLog(@"str1 = %@, str2 = %@",self.str1, self.str2);
      }
    

    在上面的代码中,分别给str1和str2赋值为同一个可变字符串变量(有人可能会疑问,为什么要赋一个可变字符串,而不是一个NSString类型的?如果赋值一个NSString类型的字符串,用strong和copy也就没有什么区别了,这一点我们后面会进行总结,在这儿我们先看它们之间的差异),执行上面的代码,打印的结果如下图:


    屏幕快照 2016-08-23 10.04.02 AM.png

    通过打印的结果我们发现:当我改变tempStr的值的时候,str1的值没有发生变化(这个是用copy修饰的), 但是str2的值发生了改变(这个是用strong修饰的),由此我们可以假设一下,str1和tempStr不是指向同一块儿内存,而str2和tempStr指向同一块儿内存,下面来验证一下:

        NSMutableString* tempStr = [@"hello" mutableCopy];
        self.str1 = tempStr;
        self.str2 = tempStr;
        NSLog(@"temStr = %p, self.str1 = %p, self.str2 = %p",tempStr,self.str1,self.str2);
        NSLog(@"str1 = %@, str2 = %@",self.str1, self.str2);
        [tempStr appendFormat:@"world"];
        NSLog(@"str1 = %@, str2 = %@",self.str1, self.str2);
    

    只是在原来的代码中加了一行指针打印,打印结果如下:

    屏幕快照 2016-08-23 10.33.25 AM.png

    果然和我们假设的一致,str1和tempStr不指向同一块儿内存,而str2和tempStr指向了同一块儿内存。那么这样就会出现一个问题:本来我们定义的str2是一个NSString类型,这就意味着我们并不想str2发生改变,但是当外界赋给它一个可变的值的时候,它却因为外界值的修改而被修改,这是我们所不愿看到的。所以上面的情况用copy修饰会更好。

    2.NSArray是不是也需要用copy来修饰?

    看了上面的情况,是不是有人会联想到像 NSArray和NSDictionary这样的可以赋给一个可变量的属性,是不是也应该用copy来修饰?下面我们还是用实例来说明。

    @interface ViewController ()
    @property (nonatomic, copy) NSArray* array1;
    @property (nonatomic, strong) NSArray* array2;
    @end
    - (void)viewDidLoad {
        [super viewDidLoad];
        // Do any additional setup after loading the view, typically from a nib.
        NSMutableArray* tempArray = [@[@"hello"] mutableCopy];
        self.array1 = tempArray;
        self.array2 = tempArray;
        NSLog(@"tempArray = %p, array1 = %p, array2 = %p, ",tempArray,self.array1,self.array2);
        NSLog(@"array1 = %@, array2 = %@",self.array1,self.array2);
        [tempArray addObject:@"world"];
        NSLog(@"array1 = %@, array2 = %@",self.array1,self.array2);
       }
    

    打印结果如下:

    屏幕快照 2016-08-23 10.50.51 AM.png

    从打印的结果我们依然可以得出: array1(也就是用copy修饰的)和tempArray不指向同一块儿内存,array2(也就是用strong修饰的)和tempArray指向了同一块儿内存,所以当我们修改tempArray的时候,array2的值也被修改了,这跟我们上面定义成NSArray,也就是不可变类型相违背,所以当我们定义一个像NSArray和NSDictionary这样有对应可变类型的属性的时候,都应该用copy。

    可能到这儿还是有人有疑问,如果我定义的属性本身就是一个可变类型的,比如NSMutableArray,那么我是应该用strong还是copy呢?如果不出意料的话,大家用的都是strong,下面我们测一下为什么strong又比copy好。还是用实例说话。

    @interface ViewController ()
    @property (nonatomic, copy) NSMutableArray* array3;
    @property (nonatomic, strong) NSMutableArray* array4;
    @end
    - (void)viewDidLoad {
        [super viewDidLoad];
       NSMutableArray* tempArray = [NSMutableArray arrayWithObject:@"hello"];
        self.array3 = tempArray;
        self.array4 = tempArray;
        NSLog(@"tempArray = %p,array3 = %p,array4 = %p",tempArray,self.array3,self.array4);
        [tempArray addObject:@"world"];
        NSLog(@"array3 = %@,array4 = %@,",self.array3,self.array4);
     }
    

    打印的结果如下:

    屏幕快照 2016-08-23 11.19.49 AM.png

    从打印的结果可以看出,array3和tempArray不是指向同一块儿内存,array4和tempArray指向同一块儿内存,所以当修改tempArray的值的时候,array4的值也跟着改了。而array4本身就是一个NSMutableArray类型,就意味着是可以被修改的,所以用strong会更好。

    • 总结一下上面的类容

    用copy还是strong主要取决于开发者的意图:当你不允许让这个属性的值被外界更改,就用copy;当你允许这个属性的值被外界所更改,就用strong。

    3. copy和mutablecopy

    对于copy和mutablecopy的区别,需要分为两种情况来谈:给不可变属性赋值和给可变属性赋值。下面先看给不可变属性赋值的情况,依然用实例说话:

    @interface ViewController ()
    @property (nonatomic, copy) NSString* str3;
    @end
    - (void)viewDidLoad {
        [super viewDidLoad];
        // Do any additional setup after loading the view, typically from a nib.
     
        NSString* tempStr = @"hello";
        self.str3 = [tempStr copy]; 
        NSLog(@"tempStr_p1 = %p, str3_p1 = %p",tempStr,self.str3);
        self.str3 = [tempStr mutableCopy];
        NSLog(@"tempStr_p2 = %p, str3_p2 = %p",tempStr,self.str3);
    }
    

    打印结果如下:

    屏幕快照 2016-08-23 6.18.58 PM.png
    • 由图打印的结果可以得出如下结论
      str3是不可变的类型,[tempStr copy]也是不可变的类型,把tempStr赋给str3,也就是把一个不可变的赋给一个不可变的,既然两个都不可变,也就是都不存在被修改的风险,所以用同一块儿内存就行了,没有必要再搞一块儿内存,所以会有上面的 tempStr_p1=str3_p1;
      但是[tempStr mutableCopy]是一个可变的类型,把[tempStr mutableCopy]赋给str3,也就是把一个可变的赋给了一个不可变的,但是这样就会出现一个问题:当可变的那个变量的值发生改变的时候,可能会导致不可变的那个变量的值也跟着改变,这就违背了开发者的意图,所以就要给str3重新分配一份儿内存,也就有了上面的 tempStr_p12 != str3_p2。

    下面再看看给可变类型的属性赋值的情况,还是用实例说话:

    @interface ViewController ()
    @property (nonatomic, strong) NSMutableString* str4;
    @end
    - (void)viewDidLoad {
        [super viewDidLoad];
        // Do any additional setup after loading the view, typically from a nib.
           NSMutableString* tempStr = [NSMutableString stringWithString:@"hello"];
        self.str4 = [tempStr copy];
        NSLog(@"tempStr_p1 = %p, str4_p1 = %p",tempStr,self.str4);
        self.str4 = [tempStr mutableCopy];
        NSLog(@"tempStr_p2 = %p, str4_p2 = %p",tempStr,self.str4);
        
    }
    

    打印结果如下图

    屏幕快照 2016-08-23 6.50.15 PM.png
    • 由图打印的结果可以得出如下的结论
      str4是可变的类型,[tempStr copy]其实是一个不可变的类型,把[tempStr copy]赋给str4,其实是把一个不可变的赋给了一个可变的,如果这两个还共用一块儿内存的话,当str4的值发生了改变,会导致[tempStr copy]这个不可变的变量的值也跟着变化,这样就矛盾了,所以就有了上面的 tempStr_p1 != str4_p1,也就是给str4重新搞一块儿内存,让str4在自己的那块儿内存中随便折腾而不影响别人;
      但是[tempStr mutableCopy]是一个可变的类型,把[tempStr mutableCopy]赋给str4,其实是把一个可变的赋给了一个可变的,那么可能有人会有疑问,既然都是可变的,那为何不共用同一块儿内存呢,为何 tempStr_p2 != str4_p2呢?我的理解是这样的:虽然[tempStr mutableCopy]是可变的,但是我不希望你str4来改变我,我要变我自己会变,所以还是给str4搞了一块儿新的内存,让str4自己玩自己的,不要去影响别人。

    • 本文属原创文章,转载请注明出处,谢谢!

    相关文章

      网友评论

          本文标题:大话strong, copy和mutablecopy

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