美文网首页架构师之路iOS 知识点ios闲来一看
iOS 浅谈:深.浅拷贝与copy.strong

iOS 浅谈:深.浅拷贝与copy.strong

作者: 汉斯哈哈哈 | 来源:发表于2015-08-11 13:38 被阅读24045次

    深.浅拷贝

    • copy/mutableCopy NSString
    NSString *string = @"汉斯哈哈哈";
    // 没有产生新对象
    NSString *copyString = [string copy];
    // 产生新对象
    NSMutableString *mutableCopyString = [string mutableCopy];
    
    NSLog(@"string = %p copyString = %p mutableCopyString = %p", string, copyString, mutableCopyString);
    
    • copy/mutableCopy NSMutableString
    NSMutableString *string = [NSMutableString stringWithString:@"汉斯哈哈哈"];
    
    // 产生新对象
    NSString *copyString = [string copy];
    // 产生新对象
    NSMutableString *mutableCopyString = [string mutableCopy];
    
    NSLog(@"string = %p copyString = %p mutableCopyString = %p", string, copyString, mutableCopyString);
    

    结论:

    注意:其他对象NSArray、NSMutableArray 、NSDictionary、NSMutableDictionary一样适用


    • copy NSObject
    HSPerson *p = [[HSPerson alloc] init];
    p.age = 20;
    p.height = 170.0;
    
    HSPerson *copyP = [p copy]; // 这里崩溃
    

    崩溃:


    看崩溃信息HSPerson应该先实现:

    - (id)copyWithZone:(NSZone *)zone;
    

    测试:

    #import "HSPerson.h"
    
    @interface HSPerson()<NSCopying>
    
    @end
    
    @implementation HSPerson
    
    - (id)copyWithZone:(NSZone *)zone
    {
    
        return @"汉斯哈哈哈";
    }
    
    @end
    
    HSPerson *p = [[HSPerson alloc] init];
    p.age = 20;
    p.height = 170.0;
    
    HSPerson *copyP = [p copy];
    NSLog(@"copyP: %@", copyP);
    

    可以看出copyWithZone重新分配新的内存空间,则:

    - (id)copyWithZone:(NSZone *)zone
    {
        HSPerson *person = [[HSPerson allocWithZone:zone] init];
        return person;
    
    // 有些人可能下面alloc,重新初始化空间,但这方法已给你分配了zone,自己就无需再次alloc内存空间了
    //    HSPerson *person = [[HSPerson alloc] init];
    }
    
    HSPerson *p = [[HSPerson alloc] init];
    p.age = 20;
    p.height = 170.0;
    
    HSPerson *copyP = [p copy];
    NSLog(@"p = %p copyP = %p", p, copyP);
    
    NSLog(@"age = %d height = %f", copyP.age, copyP.height);
    

    虽然copy了份新的对象,然而age,height值并未copy,那么:

    - (id)copyWithZone:(NSZone *)zone
    {
        HSPerson *person = [[HSPerson allocWithZone:zone] init];
        person.age = self.age;
        person.height = self.height;
        // 这里self其实就要被copy的那个对象,很显然要自己赋值给新对象,所以这里可以控制copy的属性
        return person;
    }
    

    这时你会想,有NSMutableCopying?没错,是有这货:

    - (id)mutableCopyWithZone:(NSZone *)zone
    {
        HSPerson *person = [[HSPerson allocWithZone:zone] init];
        person.age = self.age;
        person.height = self.height;
    
        return person;
    }
    

    NSCopying、NSMutableCopying有啥区别?
    其实感觉没必要有NSMutableCopying,因为压根就没可变的HSPerson,但如果该对象有其他行为,可以借用NSMutableCopying实现,哈哈哈

    property里的copy、strong区别

    说完深浅拷贝,理解property里的copy、strong就轻松多了!

    • copy
    #import <Foundation/Foundation.h>
    
    @interface HSPerson : NSObject
    
    @property (nonatomic, copy) NSString *name;
    
    @end
    
    
    NSMutableString *string = [NSMutableString stringWithFormat:@"汉斯哈哈哈"];
    
    HSPerson *person = [[HSPerson alloc] init];
    person.name = string;
    
    // 不能改变person.name的值,因为其内部copy新的对象
    [string appendString:@" hans"];
    
     NSLog(@"name = %@", person.name);
    

    property copy 实际上就对name干了这个:

    - (void)setName:(NSString *)name
    {
        _name = [name copy];
    }
    

    假设name为NSMutableString,会发生什么事?

    @property (nonatomic, copy) NSMutableString *name;
    

    这样会挨骂哦,实际上内部还是:

    - (void)setName:(NSMutableString *)name
    {
        _name = [name copy];
    }
    

    copy出来的仍然是不可变字符!如果有人用NSMutableString的方法,就会崩溃:

    • strong
    @property (nonatomic, strong) NSString *name;
    
    NSMutableString *string = [NSMutableString stringWithFormat:@"汉斯哈哈哈"];
    
    HSPerson *person = [[HSPerson alloc] init];
    person.name = string;
    
    // 可以改变person.name的值,因为其内部没有生成新的对象
    [string appendString:@" hans"];
    
    NSLog(@"name = %@", person.name);
    

    文章同步到微信公众号:hans_iOS 有疑问可以在公众号里直接发

    相关文章

      网友评论

      • 高高叔叔:NSString 本来就不是一个对象,怎么说产生一个新对象。
        copy 只是 mutableCopy 内存地址都变了 只有copy的内容地址没有变。
      • coderjon:按照上面说的,strong是浅拷贝,当是nsstring的时候,也是浅拷贝,那么为什么下面你举的例子,两个结果是不一样的?
      • d0a4ce18c0bc: NSString *name = @"naem";
        NSLog(@"---name-----%p",&name);
        NSString *newname = [name copy];
        NSLog(@"---newname-----%p",&newname);

        打印的结果是
        2017-07-29 23:13:44.332 deepCopyAndqianCopy[1785:71241] ---name-----0x7fff523639e8
        2017-07-29 23:13:44.333 deepCopyAndqianCopy[1785:71241] ---newname-----0x7fff523639e0

        这是为什么呢,和你的第一张截图违背了啊
        汉斯哈哈哈:你打印错了,这是打印指针变量name的地址:NSLog(@"---name-----%p",&name); 这是打印指针变量name存储的值:NSLog(@"---name-----%p", name);
      • iOSLover:按你的理解NSMutable* 使用 mutableCopy 是深copy那么
        NSMutableArray *element = [NSMutableArray arrayWithObject:@1];
        NSMutableArray *array = [NSMutableArray arrayWithObject:element];
        NSMutableArray *mutableCopyArray = [array mutableCopy];
        [mutableCopyArray[0] addObject:@2];
        现在我改变了 mutableCopyArray 的元素,往这个元素里加了一个 2。
        现在输出 array[0] 看看,结果是 1 和 2。
        你怎么解释这种结果
        汉斯哈哈哈:集合对象的内容复制仅限于当前集合的对象本身,对象元素仍然是指针复制
        https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/Collections/Articles/Copying.html#//apple_ref/doc/uid/TP40010162-SW3
        fb104ab6ffe5:array拷贝成mutableCopyArray的时候 里面的element是同一对象
        如果想要array和mutableCopyArray打印的数据不同,则要进行完全深拷贝,即每一层都是对象复制。
      • WonderfulBlock:_name = [name copy]; 如果这个name的字符串属性使用copy修饰,在赋值的时候是重新生成了一个对象,这个跟你上面总结的 对NSString 进行copy操作的时候是深拷贝的说法是矛盾的吧?
        deqiutseng:@遥遥锅锅 既然是两个不同的内存,但是name 被定义成NSMutableString 不应该也是可以被修改的嘛?
        丶Destinyxl:同样有点疑问 copy声明的字符串属性 被不可变字符串赋值 生成了新的内存? 不应该是浅拷贝吗?
        1c7d21358574:name进行copy操作的时候,传进去的是可变字符串,copy之后产生新的对象,跟name是两个不同的内存
      • 南坞觉:金星老师最近好吗?
        偶然ou:@南坞觉 我也想问来着 :smile:
        汉斯哈哈哈:@我的大名叫小爱 醉了... :sob:
        我的大名叫小爱:@南坞觉 哈哈 看到这儿笑啦...
      • 小生不怕:博主你好!有个问题一直很困扰我,希望博主可以帮帮我。看到网上都是说NSString的 copy不会产生新对象,但是我打印出来的内存地址都是和之前不一样的。
        NSString *str1 = @"hehe";

        NSString *str2 = [str1 copy];

        NSLog(@"str1:%p str2:%p",&str1, &str2);


        2016-05-30 00:35:35.916 TestCopy[19256:783473] str1:0x7fff5fbff7e8 str2:0x7fff5fbff7e0
        汉斯哈哈哈:@小生不怕 还有一点要区分:
        1.NSLog(@"str1:%p str2:%p",&str1, &str2);
        打印的是当前变量的地址
        2.NSLog(@"str1:%p str2:%p",str1, str2);
        打印的是当前变量存储的对象地址

        而所谓copy NSString不会产生新对象,就是当前变量存储的对象地址没变
        汉斯哈哈哈:@小生不怕 你打印的是变量str1,str2地址,肯定不一样。比方说,你声明str1,str2两个变量,在内存里就会分配两块内存来存储着这两个变量的,变量的地址分别是0x7fff5fbff7e8, 0x7fff5fbff7e0
      • 令__狐冲:strong意思是浅拷贝?
        coderjon:@汉斯哈哈哈 strong是深拷贝还是浅拷贝?一脸懵逼,求解惑
        汉斯哈哈哈:@oik_ios strong 可理解为指针的引用,用 copy 是生成了一份新的内存空间,所以外界是不能修改值,但strong可以,因为指向同一块内存~
      • Life淡淡:为什么在@property (nonatomic, copy) NSString *name; copy 必须要用copy?为什么不用strong
        lcus:copy和Strong一样的你说的这种情况没必要非得copy
        我是C:@汉斯哈哈哈 对于NS类型的copy不是相当于Strong?
        汉斯哈哈哈:@求美女过来 copy了新对象,防止外界修改name
      • 寂静的天空:为什么这个属性@property (nonatomic, copy) NSMutableString *name; copy出来的是不可变字符串啊
        汉斯哈哈哈:@寂静的天空
        因为内部实现:
        - (void)setName:(NSMutableString *)name
        {
        _name = [name copy];
        }
      • 南羽语玉的文字:http://www.cocoachina.com/bbs/read.php?tid=323045&amp;page=e&#a
        dslCoding:页面找不到了请发一个正常的谢谢
      • 南羽语玉的文字:有同学提出了以下质疑,麻烦博主回应一下?如下:
        有两个问题,第一个是用NSString、NSArray、NSDictionary来举例就是错误的,这些不可变对象是分配在静态存储区的,整个进程公用一份对象,所以无论是retain、strong,或者是深浅拷贝,对它们来说是没区别的。
        第二个是,假如对象是一个容器,例如NSMutableArray。浅拷贝是拷贝容器对象本身,但是不拷贝容器内包含的元素,而深拷贝不仅仅是拷贝容器对象本身,而且还会拷贝容易内包含的对象。
        无论是深浅拷贝,既然名称中都带有拷贝一词,它必然有一个拷贝的动作。而所谓的指针拷贝,就是objc中的retain/assign,跟拷贝没有半毛钱关系。
        肖无情:@南羽语玉 您好,“不可变对象是分配在静态存储区的,整个进程公用一份对象,所以无论是retain、strong,或者是深浅拷贝,对它们来说是没区别的:”这一个不太明白
        NSArray *arr1 = @[@"a"];
        NSArray *arr11 = @[@"a"];
        NSArray *arr2 = [arr1 copy];
        NSMutableArray *arr3 = [arr1 mutableCopy];
        [arr3 addObject:@[@"b"]];

        NSLog(@"%p_____%p_____%p______%p",arr11,arr1,arr2,arr3);
        0x608000019b90_____0x608000019b90_____0x608000019b90______0x608000044980
        这个以我是用了mutableCopy 他的指针变了,不知道你说的那个没关系是怎么理解的,


        SOI:@汉斯哈哈哈 @南羽语玉 不可变对象分配在静态存储区,麻烦粘一下苹果官网的说明,没有找到啊
        汉斯哈哈哈:@南羽语玉 是的,容器拷贝本身比较特例,所以苹果专门拿出来讲:https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/Collections/Articles/Copying.html
        感谢指出!
      • 9913e661dff4:谢谢作者分享!
      • 寂静的天空:这个必须顶 平时一直很混乱的知识
        汉斯哈哈哈:@寂静的天空 哈,谢谢支持!
      • ba08449e08cf:希望能看到你发表更多各类的文章,比如生活上😁
      • FengxinLi:我知道理论是深拷贝,但是我运行出来是改变了的,今天迷茫了一天了,但是如果像你那样新建person类name属性运行是你那样。但是不新建类。就是controller里面的属性运行起就改变了。不像你说的是深拷贝。
        汉斯哈哈哈:@Fengxinliju :sob:
        FengxinLi:@汉斯哈哈哈 我是打印的_属性。不是self.属性。我再去测试哈
        汉斯哈哈哈:@Fengxinliju
        不会啊! :cry:
        在VC里:@property (nonatomic, copy) NSString *name;

        NSMutableString *string = [NSMutableString stringWithString:@"汉斯哈哈哈"];
        self.name = string;
        [string appendString:@" - hans"];
        NSLog(@"string: %@ name: %@", string, self.name);
        打印:
        string: 汉斯哈哈哈 - hans name: 汉斯哈哈哈
      • 腊冬:赞
      • FengxinLi:@property (nonatomic, copy) NSString *name; 这样一个属性,赋值之后可以修改的。 如果不希望被外界更改 这个是指调用NSMutableString的方法吗?
        FengxinLi:@汉斯哈哈哈 可以加哈QQ不?我的QQ:1203420007
        FengxinLi:@汉斯哈哈哈 NSString 如果是copy是浅拷贝。就是指向的同一个地址。而深拷贝是重新复制指向另外一个地址来存储。那strong是深拷贝还是浅拷贝?
        汉斯哈哈哈:@Fengxinliju 你貌似理解偏了,我说的不希望被外界更改指的是在strong情况下,如果外部被引用的变量更改了,那里面这个值也会更改,因为两个属性指向同一块内存空间

      本文标题:iOS 浅谈:深.浅拷贝与copy.strong

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