美文网首页架构师之路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