本文共 12757 字,大约阅读时间需要 42 分钟。
开发中,数据处理是整个项目的重中之重,清晰的数据结构,安全高效的处理流程,能大大提高开发效率和系统的稳定性。数据是事物状态和变化的记录,具有可修改性和拷贝性,当多处使用,并有可能改变时,为了保障原数据的不变,我们需要拷贝一份新的数据,改变新的数据,而不改变原数据。数据处理中的,操作权限控制,数据的传递,数据的深、浅拷贝等。今天主要深度分析下,Copy与MutableCopy 和 Copy与Strong 区别及使用。
CSDN的排版有点糟心,抱歉。言归正传 》》》》》》》》》》
浅拷贝:指针拷贝,不产生新的对象,源对象的引用计数器+1;
深拷贝:对象拷贝,会产生新的对象,源对象的引用计数器不变;
判断是浅拷贝和深拷贝就看一下两个变量的内存地址是否一样,一样就是浅拷贝,不一样就是深拷贝,也可以改变一个变量的其中一个属性值看两者的值都会发生变化;
NSObject类提供了copy和mutableCopy方法,通过这两个方法即可拷贝已有对象的副本,主要的系统原生对象有:NSString和NSMutableString、NSArray和NSMutableArray、NSDictionary和NSMutableDictionary、NSSet和NSMutableSet。 NSValue和NSNumber 只遵守的NSCopying协议。
注意:基本数据类型(assign修饰),没有对应的指针,是直接赋值操作,没有,也无需copy 操作。
这里以NSString 和 NSMutableString为例演示说明。
NSString *string = @"copyTest"; NSString *copyString = [string copy]; NSString *mutableCopyString = [string mutableCopy]; NSMutableString *copyMutableString = [string copy]; NSMutableString *mutableCopyMutableString = [string mutableCopy]; NSLog(@"\n string = %p \n copystring = %p \n mutablecopystring = %p " "\n copyMutableString = %p \n mutableCopyMutableString = %p \n", string, copyString, mutableCopyString, copyMutableString, mutableCopyMutableString);
打印结果:
string = 0x10dc8c260 copystring = 0x10dc8c260 mutablecopystring = 0x61000007de40 copyMutableString = 0x10dc8c260 mutableCopyMutableString = 0x61000007dac0
小结论:在字符串是直接赋值的,是否生成新对象是和 = 右边有关的,如果 = 右边是mutableCopy才会生成新对象。
NSMutableString *string = [NSMutableString stringWithString:@"学习研究"]; NSString *copyString = [string copy]; NSString *mutableCopyString = [string mutableCopy]; NSMutableString *copyMutableString = [string copy]; NSMutableString *mutableCopyMutableString = [string mutableCopy]; NSLog(@"\n string = %p \n copystring = %p \n mutablecopystring = %p " "\n copyMutableString = %p \n mutableCopyMutableString = %p \n", string, copyString, mutableCopyString, copyMutableString, mutableCopyMutableString);
string = 0x600000268e40 copystring = 0x600000221340 mutablecopystring = 0x600000268f40 copyMutableString = 0x600000221260 mutableCopyMutableString = 0x600000268fc0
注意:其他对象NSArray、NSMutableArray 、NSDictionary、NSMutableDictionary、NSSet、NSMutableSet一样适用。
实际开发中,所使用的数据模型基本都是自定义对象,并常见自定义对象的嵌套使用,我们如何实现自定义对象的深度拷贝呢?
创建两个对象 PersonItem、DogItem,.m文件中暂时不做处理,.h文件参考如下:
DogItem.h
#importPersonItem.h@interface DogItem : NSObject @property (nonatomic, copy) NSString *dogName;@end
#import#import "DogItem.h"@interface PersonItem : NSObject@property (nonatomic, copy) NSString *name;@property (nonatomic, assign) NSUInteger age;@property (nonatomic, strong) DogItem *dog;@end
PersonItem *person = [[PersonItem alloc] init]; person.name = @"person"; person.age = 100; DogItem *dog = [[DogItem alloc] init]; dog.dogName = @"dog"; person.dog = dog; //拷贝对象 PersonItem *copyPerson = [person copy]; NSLog(@"\n person: %p name = %p dog = %p", person, person.name, person.dog); NSLog(@"\n copyPerson: %p name = %p dog = %p", copyPerson, copyPerson.name,copyPerson.dog); // 更新数据 copyPerson.name = @"copy"; copyPerson.dog.dogName = @"xiaohuang"; NSLog(@"\n person.name: %@ copyPerson.name = %@", person.name, copyPerson.name); NSLog(@"\n person.dog.dogName: %@ copyPerson.dog.dogName = %@", person.dog.dogName, copyPerson.dog.dogName); NSLog(@"\n person: %p name = %p dog = %p", person, person.name, person.dog); NSLog(@"\n copyPerson: %p name = %p dog = %p", copyPerson, copyPerson.name,copyPerson.dog);
-[PersonItem copyWithZone:]: unrecognized selector sent to instance 0x60000003d3e0我们需要实现
- (id)copyWithZone:(NSZone *)zone{}//或- (id)mutableCopyWithZone:(NSZone *)zone{}
在自定义对象的.m文件中实现copyWithZone: 方法,主要实现形式有一下四种。
- (id)copyWithZone:(NSZone *)zone{ return self;}
打印结果:
person: 0x61800002cd80 name = 0x1054e5118 dog = 0x618000006370 copyPerson: 0x61800002cd80 name = 0x1054e5118 dog = 0x618000006370 person.name: copy copyPerson.name = copy person.dog.dogName: xiaohuang copyPerson.dog.dogName = xiaohuang person: 0x61800002cd80 name = 0x1054e5198 dog = 0x618000006370 copyPerson: 0x61800002cd80 name = 0x1054e5198 dog = 0x618000006370
- (id)copyWithZone:(NSZone *)zone{ PersonItem *personCopy = [[PersonItem allocWithZone:zone] init]; personCopy.name = self.name; personCopy.age = self.age; personCopy.dog = self.dog; return personCopy;}打印结果:
person: 0x60000003d480 name = 0x10b455118 dog = 0x60000001de80 copyPerson: 0x60000003c2e0 name = 0x10b455118 dog = 0x60000001de80 person.name: person copyPerson.name = copy person.dog.dogName: xiaohuang copyPerson.dog.dogName = xiaohuang person: 0x60000003d480 name = 0x10b455118 dog = 0x60000001de80 copyPerson: 0x60000003c2e0 name = 0x10b455198 dog = 0x60000001de80
- (id)copyWithZone:(NSZone *)zone{ PersonItem *personMutableCopy = [[PersonItem allocWithZone:zone] init]; personMutableCopy.name = [self.name mutableCopy]; // assign 修饰的基本数据类型,没有对应的指针,可以直接赋值操作,没有也无需copy操作。 personMutableCopy.age = self.age; personMutableCopy.dog = [self.dog copy]; return personMutableCopy;}打印结果:
person: 0x600000024aa0 name = 0x102a9d118 dog = 0x600000002100 copyPerson: 0x600000024ba0 name = 0x60000006ac80 dog = 0x6000000020f0 person.name: person copyPerson.name = copy person.dog.dogName: dog copyPerson.dog.dogName = xiaohuang person: 0x600000024aa0 name = 0x102a9d118 dog = 0x600000002100 copyPerson: 0x600000024ba0 name = 0x102a9d198 dog = 0x6000000020f0
- (id)copyWithZone:(NSZone *)zone{ PersonItem *personCopy = [[PersonItem alloc] init]; personCopy.name = self.name; personCopy.age = self.age; DogItem *dog = [[DogItem alloc] init]; dog.dogName = self.dog.dogName; personCopy.dog = dog; return personCopy;}打印结果:
person: 0x61800003fe80 name = 0x1030f3118 dog = 0x61800000fb30 copyPerson: 0x61800003fd20 name = 0x1030f3118 dog = 0x61800000fb60 person.name: person copyPerson.name = copy person.dog.dogName: dog copyPerson.dog.dogName = xiaohuang person: 0x61800003fe80 name = 0x1030f3118 dog = 0x61800000fb30 copyPerson: 0x61800003fd20 name = 0x1030f3198 dog = 0x61800000fb60
mutableCopyWithZone和copyWithZone: 一样是个待实现的方法,关键的区别在于内部实现的区别。通常,copyWithZone: 做自定义对象的单层拷贝处理(有容器嵌套的化,只copy最外一层)。mutableCopyWithZone: 做自定义对象的完全拷贝处理(有容器嵌套的化,容器中每一层对象都做拷贝处理)。
说完深浅拷贝,现在让我们一起梳理下property里的copy、strong的区别。
以NSString为例说明下,首先定义以下属性。
@property (nonatomic, strong) NSString *strongString;@property (nonatomic, copy) NSString *copyedString;@property (nonatomic, strong) NSMutableString *strongMutableString;@property (nonatomic, copy) NSMutableString *copyedMutableString;
- (void)testPropertyCopyOrStrong{ NSString *string = [NSString stringWithFormat:@"abc"]; self.strongString = string; self.strongMutableString = string; self.copyedString = string; self.copyedMutableString = string; string = [string stringByReplacingOccurrencesOfString:@"c" withString:@"233"]; NSLog(@"\n origin string: %p, %p %@ %@", string, &string, string, NSStringFromClass([string class])); NSLog(@"\n strong string: %p, %p %@ %@", _strongString, &_strongString, _strongString, NSStringFromClass([_strongString class])); NSLog(@"\n strongMutable string: %p, %p %@ %@", _strongMutableString, &_strongMutableString, _strongMutableString, NSStringFromClass([_strongMutableString class])); NSLog(@"\n copy string: %p, %p %@ %@", _copyedString, &_copyedString, _copyedString, NSStringFromClass([_copyedString class])); NSLog(@"\n copyMutable string: %p, %p %@ %@", _copyedMutableString, &_copyedMutableString, _copyedMutableString, NSStringFromClass([_copyedMutableString class]));}
打印结果:
origin string: 0x103a74098, 0x7fff5c18ca88 ab233 __NSCFString strong string: 0xa000000006362613, 0x7f84c9f056d8 abc NSTaggedPointerString strongMutable string: 0xa000000006362613, 0x7f84c9f056e8 abc NSTaggedPointerString copy string: 0xa000000006362613, 0x7f84c9f056e0 abc NSTaggedPointerString copyMutable string: 0xa000000006362613, 0x7f84c9f056f0 abc NSTaggedPointerString
- (void)testPropertyCopyOrStrong{ NSMutableString *string = [NSMutableString stringWithFormat:@"abc"]; self.strongString = string; self.strongMutableString = string; self.copyedString = string; self.copyedMutableString = string; [string appendString:@"123"]; NSLog(@"\n origin string: %p, %p %@ %@", string, &string, string, NSStringFromClass([string class])); NSLog(@"\n strong string: %p, %p %@ %@", _strongString, &_strongString, _strongString, NSStringFromClass([_strongString class])); NSLog(@"\n strongMutable string: %p, %p %@ %@", _strongMutableString, &_strongMutableString, _strongMutableString, NSStringFromClass([_strongMutableString class])); NSLog(@"\n copy string: %p, %p %@ %@", _copyedString, &_copyedString, _copyedString, NSStringFromClass([_copyedString class])); NSLog(@"\n copyMutable string: %p, %p %@ %@", _copyedMutableString, &_copyedMutableString, _copyedMutableString, NSStringFromClass([_copyedMutableString class]));}
打印结果:
origin string: 0x60000006cec0, 0x7fff5417ea88 abc123 __NSCFString strong string: 0x60000006cec0, 0x7fc702508148 abc123 __NSCFString strongMutable string: 0x60000006cec0, 0x7fc702508158 abc123 __NSCFString copy string: 0xa000000006362613, 0x7fc702508150 abc NSTaggedPointerString copyMutable string: 0xa000000006362613, 0x7fc702508160 abc NSTaggedPointerString
@property (nonatomic, strong) NSString *strongString;@property (nonatomic, copy) NSString *copyedString;@property (nonatomic, strong) NSMutableString *strongMutableString;@property (nonatomic, copy) NSMutableString *copyedMutableString;
- (void)setStrongString:(NSString *)strongString{ _strongString = strongString;}
- (void)setCopyedString:(NSString *)copyedString{ _copyedString = [copyedString copy];}
- (void)setStrongMutableString:(NSMutableString *)strongMutableString{ _strongMutableString = strongMutableString;}
- (void)setCopyedMutableString:(NSMutableString *)copyedMutableString{ _copyedMutableString = [copyedMutableString copy];}
@property (nonatomic, copy) NSString *copyedString;@property (nonatomic, strong) NSMutableString *strongMutableString;