• [OC Foundation框架


    一个对象使用copy或mutableCopy方法可以创建对象的副本

    1.copy
    需要实现NSCopying协议
    创建出来的是不可变副本,如NSString, NSArray, NSDictionary
     
    (1)不可变对象调用copy  (NSSring除外)
    不会产生新的对象,而是返回对象本身,相当于retain,计数器+1
    属于浅拷贝
     
    复制代码
     1         NSArray *arr1 = [NSArray arrayWithObjects:@"张三", @"李四", nil];
     2         NSLog(@"arr1.addr: %p", arr1); // 0x1002052b0
     3         NSLog(@"arr1.retainCount: %ld", arr1.retainCount); // 1
     4 
     5        
     6         NSArray *arr2 = [arr1 copy];
     7         NSLog(@"arr1.addr: %p", arr1); // 0x1002052b0
     8         NSLog(@"arr1.retainCount: %ld", arr1.retainCount); // 2  <-- 浅拷贝,相当于retain, retainCount+1
     9         NSLog(@"arr2.addr: %p", arr2); //0x1002052b0 <-- 浅拷贝,依旧指向同一个对象
    10         NSLog(@"arr2.retainCount: %ld", arr2.retainCount); // 2 <-- 浅拷贝,还是原来对象的retainCount
    复制代码
     
    (2)可变对象调用copy (NSMutableString会拷贝出一个NSString”常量对象")
    返回一个不可变对象,但是不是原来的对象,属于深拷贝
    复制代码
     1         NSMutableArray *arr1 = [NSMutableArray array];
     2         [arr1 addObject:@"123"];
     3         [arr1 addObject:@"abc"];
     4         NSLog(@"arr1.addr: %p", arr1); // 0x100204840
     5         NSLog(@"arr1.retainCount: %ld", arr1.retainCount); // 1
     6        
     7        
     8         NSMutableArray *arr2 = [arr1 copy];
     9         NSLog(@"arr1.addr: %p", arr1); // 0x100204840
    10         NSLog(@"arr1.retainCount: %ld", arr1.retainCount); // 1 <-- 深拷贝,原来的对象retainCount保持
    11         NSLog(@"arr2.addr: %p", arr2); // 0x100300000 <-- 深拷贝,开辟了新的内存空间,拷贝出来的实际对象是NSArray
    12         NSLog(@"arr2.retainCount: %ld", arr2.retainCount); // 1 <-- 深拷贝,新的对象retainCount独立
    复制代码
     
    (3)重点: NSString的特殊性
    由于使用了 @“” 进行初始化,数据存放在了常量池
     
    因为NSString指向字符串常量,系统不会收回,也不会对其作引用计数,即使我们对NSString变量如何retain或release,retainCount都是-1 (无符号最大值)
    复制代码
     1         NSString *str1 = [[NSString alloc] initWithString:@"abc"];
     2         NSLog(@"str1.addr: %p", str1); // 0x100001030
     3         NSLog(@"str1.retainCount: %ld", str1.retainCount); // -1 <-- 字符串常量存在常量池,不使用堆内存
     4        
     5         NSString *str2 = [str1 copy];
     6         NSLog(@"str1.addr: %p", str1); // 0x100001030
     7         NSLog(@"str1.retainCount: %ld", str1.retainCount); // -1 <-- 无论是copy, retain, release操作都不会改变retianCount
     8         NSLog(@"str2.addr: %p", str2); // 0x100001030 <-- 拷贝之后的变量依旧指向原来的常量
     9         NSLog(@"str2.retainCount: %ld", str2.retainCount); // -1 <-- 原来常量的retainCount
    10        
    11         [str1 retain];
    12         NSLog(@"after retain -> str1.retainCount: %ld", str1.retainCount); // -1 <-- 无论是copy, retain, release操作都不会改变retianCount
    13         [str2 release];
    14         NSLog(@"after release -> str2.retainCount: %ld", str2.retainCount); // -1 <-- 无论是copy, retain, release操作都不会改变retianCount
    复制代码
     
    要使一个NSString变量也有retainCount:
    就要是指向另外一个”NSString”对象,而不是字符串常量
    1         // 先创建出一个NSString对象,再用另一个指向
    2         NSString *str1 = [NSString stringWithFormat:@"abc"];
    3         NSLog(@"%ld", str1.retainCount); // -1
    4         NSString *str2 = [NSString stringWithString:str1];
    5         NSLog(@"%ld", str2.retainCount); // 1
     
    (4)copy出来的是不可变对象,如NSMutableString调用copy创建出来的实际是NSString
    复制代码
     1         // 这里不能使用 NSMutableString *mstr1 = @"abc", 或者在延迟赋值 mstr1 = @"abc"; 否则同样指向常量池
     2         NSMutableString *mstr1 = [[NSMutableString alloc] initWithString:@"abc"];
     3         NSLog(@"mstr1.addr: %p", mstr1); // 0x100404990
     4         NSLog(@"mstr1.retainCount: %ld", mstr1.retainCount); // 1
     5 
     6 
     7         NSMutableString *mstr2 = [mstr1 copy];
     8         NSLog(@"mstr1.addr: %p", mstr1); // 0x100404990
     9         NSLog(@"mstr1.retainCount: %ld", mstr1.retainCount); // 1 <-- 深拷贝,原来的对象retainCount保持
    10         NSLog(@"mstr2.addr: %p", mstr2); // 0x63626135 <-- 深拷贝,开辟了新的内存空间,但是指向的实际是一个字符串常量
    11         NSLog(@"mstr2.retainCount: %ld", mstr2.retainCount); // -1 <-- 因为其实拷贝出来的是一个字符串常量
    复制代码
    2.mutableCopy
    需要实现NSMutableCopying协议
    创建的是可变副本,如NSMutableString, NSMutableArray, NSMutableDictionary
     
    (1)不可变对象调用mutableCopy
    产生一个新的对象,新旧对象的计数器独立,不会互相干扰,属于深拷贝
    复制代码
    1         NSString *str1 = [[NSString alloc] initWithString:@"abc"];
    2         NSLog(@"str1.addr: %p", str1); // 0x100001030
    3         NSLog(@"str1.retainCount: %ld", str1.retainCount); // -1 <-- 字符串常量存在常量池,不使用堆内存
    4 
    5         NSMutableString *mstr2 = [str1 mutableCopy]; // mutableCopy 出来的是一个 NSMutableString 对象
    6         NSLog(@"str1.addr: %p", str1); // 0x100001030
    7         NSLog(@"str1.retainCount: %ld", str1.retainCount); // -1 <-- 对于字符串常量, 无论是copy, retain, release操作都不会改变retianCount
    8         NSLog(@"mstr2.addr: %p", mstr2); // 0x100106460 <-- 深拷贝,开辟新的空间
    9         NSLog(@"mstr2.retainCount: %ld", mstr2.retainCount); // 1 <-- 由于是NSMutableString对象,retainCount == 1
    复制代码
     
    (2)可变对象调用mutableCopy
    产生一个新的对象,新旧对象的计数器独立,不会互相干扰,属于深拷贝
    复制代码
    1         NSMutableString *mstr1 = [[NSMutableString alloc] initWithString:@"abc"];
    2         NSLog(@"mstr1.addr: %p", mstr1); // 0x100402910
    3         NSLog(@"mstr1.retainCount: %ld", mstr1.retainCount); // 1
    4 
    5         NSMutableString *mstr2 = [mstr1 mutableCopy]; // mutableCopy 出来的是一个 NSMutableString 对象
    6         NSLog(@"mstr1.addr: %p", mstr1); // 0x100402910
    7         NSLog(@"mstr1.retainCount: %ld", mstr1.retainCount); // 1
    8         NSLog(@"mstr2.addr: %p", mstr2); // 0x100300e90 <-- 深拷贝,开辟新的空间
    9         NSLog(@"mstr2.retainCount: %ld", mstr2.retainCount); // 1
    复制代码
     
    3.自定义类的copy
    1 @interface Student : NSObject
    2 
    3 //copy代表setter会release旧对象,copy新对象
    4 @property (nonatomic, copy) NSString *name;
    5 
    6 @end
     
    传入外部NSMutableString对象到student的setter,当外部对象改变的时候,不会改变student中copy来的对象
    如果使用retain或者assign,就会影响,因为指向的是同一个对象
    ==>传入NSMutableString时(成员变量为NSString),一般使用copy策略,其他使用retain
     
    (1)实现<NSCopying>
    (2)实现 - (id) copyWithZone:(NSZone *) zone
    1 - (id)copyWithZone: (NSZone *) zone
    2 {
    3      Student *stu = [[Student allocWithZone:zone] init];
    4      stu.name = self.name;
    5      return stu;
    6 }
    如果一件事情你觉得难的完不成,你可以把它分为若干步,并不断寻找合适的方法。最后你发现你会是个超人。不要给自己找麻烦,但遇到麻烦绝不怕,更不要退缩。 电工查找电路不通点的最快方法是:分段诊断排除,快速定位。你有什么启示吗? 求知若饥,虚心若愚。 当你对一个事情掌控不足的时候,你需要做的就是“梳理”,并制定相应的规章制度,并使资源各司其职。
  • 相关阅读:
    Error.prototype (Errors) – JavaScript 中文开发手册
    C 库函数 – isalnum()
    git diff-files (Git) – Git 中文开发手册
    Java面试题:如何在基于Java的Web项目中实现文件上传和下载?
    HTML onload 属性
    JavaScript setDate() 方法
    Linux fsconf命令
    HTML DOM Reset disabled 属性
    wcsstr (Strings) – C 中文开发手册
    HTML area shape 属性
  • 原文地址:https://www.cnblogs.com/wvqusrtg/p/4515328.html
Copyright © 2020-2023  润新知