iOS之深浅拷贝

2018-08-15  本文已影响13人  Coder_Cat

1.深拷贝和浅拷贝概念

深拷贝和浅拷贝

2.copy和mutableCopy

3.OC中的非集合类对象和集合类对象的深浅拷贝

一. 非集合类对象:NSString,NSMutableString,NSData,NSNumber
非集合对象的copymutableCopy
示例1:

        NSString *str1 = @"字符串1";
        NSString *str2 = [str1 copy];
        NSMutableString *str3 = [str1 mutableCopy];
        
        NSMutableString * str4 = [NSMutableString stringWithString:@"字符串2"];
        NSString * str5 = [str4 copy];
        NSMutableString *str6 = [str4 mutableCopy];

打断点lldb调试:

非集合对象的copy与mutableCopy.png
        NSArray * arr1 = [NSArray arrayWithObjects:@1,@2,@3,nil];
        NSArray * arr2 = [arr1 copy];
        NSMutableArray * arr3 = [arr1 mutableCopy];
        
        NSMutableArray * arr4 = [NSMutableArray arrayWithObjects:@4,@5,@6,nil];
        NSArray * arr5 = arr4.copy;
        NSMutableArray * arr6 = arr4.mutableCopy;

打断点lldb调试:

集合对象的copy与mutableCopy.png
源对象类型 拷贝方式 目标对象类型 是否开辟新内存 拷贝类型
不可变对象 copy 不可变对象 浅拷贝(指针拷贝)
不可变对象 mutableCopy 可变对象 深拷贝(内容拷贝)
可变对象 copy 不可变对象 深拷贝(内容拷贝)
可变对象 mutableCopy 可变对象 深拷贝(内容拷贝)

4.property中copy关键字

@property (nonatomic, copy) NSArray *array;

- (void)setArray:(NSArray *)array {
_array = [array copy];  
}

此时不管传进来的arrayNSArray还是NSMutableArray类型都会产生一个array copy 了一个副本,是不可变的。

如果我们直接用strong关键字的话,又是怎样的呢?
示例4:

@property (nonatomic, strong) NSArray *array;

- (void)setArray:(NSArray *)array {
_array = array;  
}

如果此时传入的array是一个NSMutableArray的话,self.array可能会在不知情的情况下被修改。

@interface Person : NSObject
@property(nonatomic ,strong) NSString * name;
@property(nonatomic ,copy) NSString * age;
@end

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        Person * p = [[Person alloc]init];
        NSMutableString * name = [NSMutableString stringWithFormat:@"马云爸爸"];
        p.name = name;
        NSLog(@"name修改前:%@", p.name);
        [name appendString:@"和马化腾岳父谁厉害?"];
        NSLog(@"name修改后:%@", p.name);
        
        NSMutableString * age = [NSMutableString stringWithFormat:@"马云爸爸50岁"];
        p.age = age;
        NSLog(@"age修改前:%@", p.age);
        [age appendString:@"马化腾岳父45岁"];
        NSLog(@"age修改后:%@", p.age);
    }
    return 0;
}

打印结果

property中copy关键字.png
结果分析:Personname属性用了strong修饰,当传进来的NSMutableString类型的name变量值改变后Personname属性值也发生了改变(父类指针指向子类,多态),而我们并没有对Personname属性直接操作,这样是不合理的;而Personage属性用了copy修饰,不管传进来的变量是不是可变的字符串,都只会拷贝一份指针而指向该块内存,当可变的字符串age值发生改变时(内存发生了改变),属性age还是指向该块内存,不会改变。
@interface Person : NSObject
@property(nonatomic ,copy) NSMutableString * name;
@end

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        Person * p = [[Person alloc]init];
        NSMutableString * name = [NSMutableString stringWithFormat:@"马云爸爸"];
        p.name = name;
        [p.name appendString:@"和马化腾岳父谁厉害?"];
    }
    return 0;
}
copy修饰可变对象.png
crash原因是:尝试使用appendString改变不可变对象

5.自定义对象使用copy和mutableCopy。

如果想自定义对象使用copymutableCopy,只需要分别遵守NSCopying,NSMutableCopying协议,然后实现- (id)copyWithZone:(nullable NSZone *)zone;- (id)mutableCopyWithZone:(nullable NSZone *)zone;方法。
示例7:

#import <Foundation/Foundation.h>
@interface Person : NSObject<NSCopying,NSMutableCopying>
@property(nonatomic ,copy) NSString * name;
@property(nonatomic ,copy) NSString * age;
@end

#import "Person.h"
@implementation Person
-(id)copyWithZone:(NSZone *)zone{
    Person * p = self;
    return p;
}
-(id)mutableCopyWithZone:(NSZone *)zone{
    Person * p = [[Person allocWithZone:zone] init];
    p.name = self.name;
    p.age = self.age;
    return p;
}

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        Person * p1 = [[Person alloc]init];
        p1.name = @"马云";
        p1.age = @"55";
        Person * p2 = [p1 copy];
        Person * p3 = [p1 mutableCopy];
    }
    return 0;
}
自定义对象使用copy和mutableCopy.png
上一篇 下一篇

猜你喜欢

热点阅读