美文网首页学无止境iOS精学选辑iOS模块详解
为什么声明NString,NSArray等需要使用copy,使用

为什么声明NString,NSArray等需要使用copy,使用

作者: 轶匠 | 来源:发表于2017-06-03 11:35 被阅读3393次

    一、为什么@property声明(NString,NSArray,NSDictionary)时需要使用copy,使用strong有什么问题。

    • 因为NString,NSArray,NSDictionary都有自己对应的子类:NSMutableString,NSMutableArray,NSMutableDictionary,而父类指针可以指向子类对象,使用copy可以让本对象不受外界(子对象)影响,无论给我传入的是一个可变对象还是一个不可变对象,都能保证自身持有的是一个不可变副本。
    • 使用strong时,如果这个属性指向一个可变对象,修改可变对象时,这个属性值也会被修改。

    举例说明:

    定义两个属性string和array用strong修饰

    @interface ViewController ()
    @property (strong, nonatomic) NSString *string;
    @property (strong, nonatomic) NSArray *array;
    @end
    
      - (void)viewDidLoad {
        NSMutableString * mString = [NSMutableString stringWithString:@"123"];
        self.string = mString;
        [mString appendString:@"666"];
        NSLog(@"%@",self.string);
        
        NSMutableArray *mArray = [NSMutableArray arrayWithObjects:@1,@2,@3, nil];
        self.array = mArray;
        [mArray addObject:@6];
        NSLog(@"%@",self.array);
    }
    

    打印结果:

    2017-06-02 17:43:22.440 测试Test[45671:7372719] 123666
    2017-06-02 17:43:22.441 测试Test[45671:7372719] (
        1,
        2,
        3,
        6
    )
    

    这里的属性string和array分别被赋值子类可变对象mString和mArray,再分别修改mString和mArray导致string和array都被修改了。
    下面看看使用copy关键字后的结果:

    @interface ViewController ()
    @property (copy, nonatomic) NSString *string;
    @property (copy, nonatomic) NSArray *array;
    @end
    

    viewDidLoad中的代码不变,打印结果:

    2017-06-02 17:48:32.583 测试Test[45795:7380495] 123
    2017-06-02 17:48:32.583 测试Test[45795:7380495] (
        1,
        2,
        3
    )
    

    属性string和array都没有被修改。所以使用copy能保证属性不被子类对象修改时同时被修改。

    二、深拷贝和浅拷贝

    • 深拷贝:内容的拷贝
    • 浅拷贝:地址的拷贝

    1、对非集合对象的copy和mutableCopy

    - (void)viewDidLoad {
        [super viewDidLoad];
        
        NSString *string = @"123";
        NSString *stringCopy = [string copy];
        NSLog(@"string的地址:%p,stringCopy的地址:%p",string,stringCopy);
        NSMutableString *stringMCopy = [string mutableCopy];
        NSLog(@"stringMCopy的地址:%p",stringMCopy);
        
        NSMutableString * mString = [NSMutableString stringWithString:@"123"];
        NSString *mStringCopy = [mString copy];
        NSLog(@"mString的地址:%p,mStringCopy的地址:%p",mString,mStringCopy);
        NSMutableString *mStringMCopy = [mString mutableCopy];
        NSLog(@"mStringMCopy的地址:%p",mStringMCopy);
    
    }
    

    打印结果:

    2017-06-03 10:22:58.643 测试Test[61063:7767634] string的地址:0x10d696078,stringCopy的地址:0x10d696078
    2017-06-03 10:22:58.644 测试Test[61063:7767634] stringMCopy的地址:0x61000006a640
    2017-06-03 10:22:58.644 测试Test[61063:7767634] mString的地址:0x61000006d040,mStringCopy的地址:0xa000000003332313
    2017-06-03 10:22:58.644 测试Test[61063:7767634] mStringMCopy的地址:0x600000072200
    

    可以得出结论非集合对象的copy和mutableCopy:

    • [immutableObject copy]是浅拷贝
    • [immutableObject mutableCopy]是深拷贝
    • [mutableObject copy]是深拷贝
    • [mutableObject mutableCopy]是深拷贝

    2、对集合对象的copy和mutableCopy

    集合对象指的是NSArray,NSDictionary,NSSet等类的对象。

    - (void)viewDidLoad {
        [super viewDidLoad];
    
        NSArray *array = @[@1, @2, @3, @4];
        NSArray *arrayCopy = [array copy];
        NSMutableArray *arrayMCopy = [array mutableCopy];
        NSLog(@"array的地址:%p,arrayCopy的地址:%p,arrayMCopy的地址:%p",array,arrayCopy,arrayMCopy);
    
        NSMutableArray *mArray = [NSMutableArray arrayWithObjects:@1, @2, @3, @4, nil];
        NSArray *mArrayCopy = [mArray copy];
        NSMutableArray *mArrayMCopy = [mArray mutableCopy];
        NSLog(@"mArray的地址:%p,mArrayCopy的地址:%p,mArrayMCopy的地址:%p",mArray,mArrayCopy,mArrayMCopy);
    
    }
    

    打印结果:

    2017-06-03 10:50:14.247 测试Test[61941:7806421] array的地址:0x600000058090,arrayCopy的地址:0x600000058090,arrayMCopy的地址:0x600000057b50
    2017-06-03 10:50:14.247 测试Test[61941:7806421] mArray的地址:0x6100000556c0,mArrayCopy的地址:0x610000055780,mArrayMCopy的地址:0x610000055870
    

    可以得出结论集合对象的copy和mutableCopy和非集合对象相同的结果:

    • [immutableObject copy]是浅拷贝
    • [immutableObject mutableCopy]是深拷贝
    • [mutableObject copy]是深拷贝
    • [mutableObject mutableCopy]是深拷贝

    注意事项:
    集合对象的深拷贝只是对象本身,而集合对象的元素还是地址的拷贝,即单层深拷贝:

    - (void)viewDidLoad {
        [super viewDidLoad];
        
        NSMutableArray *mArray1 = [NSMutableArray arrayWithObjects:@2, @2, @3, @4, nil];
        
        NSArray *array = @[mArray1, @2, @3, @4];
        NSArray *arrayCopy = [array copy];
        NSMutableArray *arrayMCopy = [array mutableCopy];
        NSLog(@"array的地址:%p,arrayCopy的地址:%p,arrayMCopy的地址:%p",array,arrayCopy,arrayMCopy);
    
        NSMutableArray *mArray = [NSMutableArray arrayWithObjects:mArray1, @2, @3, @4, nil];
        NSArray *mArrayCopy = [mArray copy];
        NSMutableArray *mArrayMCopy = [mArray mutableCopy];
        NSLog(@"mArray的地址:%p,mArrayCopy的地址:%p,mArrayMCopy的地址:%p",mArray,mArrayCopy,mArrayMCopy);
        
        NSLog(@"array的第一个元素地址:%p,arrayMCopy的第一个元素地址:%p",array[0],arrayMCopy[0]);
        NSLog(@"mArray的第一个元素地址:%p,mArrayMCopy的第一个元素地址:%p",mArray[0],mArrayMCopy[0]);
    
    }
    

    打印结果:

    2017-06-03 11:08:52.382 测试Test[62621:7832878] array的地址:0x618000054c70,arrayCopy的地址:0x618000054c70,arrayMCopy的地址:0x618000054cd0
    2017-06-03 11:08:52.382 测试Test[62621:7832878] mArray的地址:0x600000056020,mArrayCopy的地址:0x600000055fc0,mArrayMCopy的地址:0x600000056080
    2017-06-03 11:08:52.383 测试Test[62621:7832878] array的第一个元素地址:0x6180000548e0,arrayMCopy的第一个元素地址:0x6180000548e0
    2017-06-03 11:08:52.383 测试Test[62621:7832878] mArray的第一个元素地址:0x6180000548e0,mArrayMCopy的第一个元素地址:0x6180000548e0
    

    三、block为什么要使用copy

    block使用copy是在MRC中延续下来的,在MRC下,方法内部的block是存放在栈区,使用copy会将block拷贝到堆区。
    在ARC下编译器会自动对block进行copy,因此我们使用copy或者strong的效果是一样的。但是我们在ARC下继续使用copy可以提醒我们编译器会自动帮我们实现copy的操作。


    参考链接:《招聘一个靠谱的 iOS》-参考答案上

    相关文章

      网友评论

      • 天山雪莲_38324:对于集合对象和非集合对象,只有不可变对象的不可变拷贝才是浅拷贝,其余皆为深拷贝。
      • 梁森的简书:我修饰对象(除了NSString)用的都是strong
        轶匠:@梁森森 一般用strong不会有问题
      • 小王在努力:个人感觉浅拷贝是指针拷贝(指针指向同一块地址),深拷贝是地址拷贝(指针指向不同地址)。文章描述很详细
      • 如梦一般:什么深拷贝啊?这么翻译的话mutablearray应该叫深数组了🏌🏌🏌🏌
      • 五蕴盛:测试用心了,大佬.
      • shenzhenboy:"对非集合对象的copy和mutableCopy "
        非集合对象的 `copy` 和 `mutableCopy` 和深浅拷贝没有关系吧。
      • CoderQY:喜欢你的论证方式,感觉是严谨的工科思维,赞!
        轶匠:@自称程序猿的厨子 :kissing_heart:
      • Flum_X:深浅拷贝写的不错:+1:
        轶匠:@大雄不会飞 :smiley:
      • 吃蘑菇De大灰狼:NSString一般不希望被修改,所以使用copy可以保证在被赋值Mutable字符串的时候不会被修改,之前写了一篇关于深浅Copy的记录,http://www.jianshu.com/p/850c4063de3c, 欢迎拍砖:smiley:
      • 8ca7f7d26a3d:下面几个结论是不是写的矛盾啊
        [immutableObject copy]是浅拷贝
        [immutableObject mutableCopy]是深拷贝
        [immutableObject copy]是深拷贝
        [immutableObject mutableCopy]是深拷贝
        轶匠:@swsdyg 已经改了
        轶匠:@swsdyg 对,我写错了,改一下
      • __________mo:看了那么多解释,你的解释浅显易懂。
        轶匠:@__________mo :stuck_out_tongue_winking_eye::smile:过奖了

      本文标题:为什么声明NString,NSArray等需要使用copy,使用

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