copy

1.深拷贝和浅拷贝

  • 对于非集合对象
  • copy:因为copy默认返回的是不可变的,所以当我们对一个不可变的字符串进行copy的时候,我们只是拷贝了它的指针(浅拷贝)。当我们对一个可变的字符串进行拷贝的时候,因为类型转变了,我们需对其进行深拷贝。
  • mutableCopy:默认返回的是一个可变的对象,适用于可变的对象,例如NSMutableString,NSMutableArray,NSMutableDictionary、etc。 无论对于可变的字符串还是不可变的字符串进行mutableCopy,系统都默认进行深拷贝,那么为什么对于相同类型的进行mutableCopy返回的仍然是新的对象呢,因为在这里系统要保证,旧的对象和新的对象都是可变的,切他们之前不会相互影响。
  • 对于集合对象
  • 对于不可变的集合对象,copy 是浅拷贝,mutableCopy 是单层深拷贝。
  • 对于可变的集合对象,无论 copy 或者 mutableCopy 都是单层深拷贝。
 /*
     内存管理原则:
     一次alloc 对应一次release
     一次retain 对应一次 release
     一次copy 对应一次release
     有加就有减
     
     总结:
     如果是浅拷贝:不会生成新的对象,但是系统就会对原来的对象进行retain,
     所以需要对原来的对象进行一次
     
     如果是深拷贝:会生成新的对象,系统不会对原来的对象进行retain,但是因为生成了新的对象,所以我们需要对新的对象进行release
     */

    //1.创建一个不可变字符串
    NSString *str = [[NSString alloc]initWithFormat:@"lnj"];
    NSLog(@"str = %lu", [str retainCount]);
    
    /*
     
     
     
     */
    //不会生成新的对象,但是需要注意,正是因为不会生产新的对象,所以系统会对以前的对象进行一次retain
    //如果是浅拷贝,那么系统就会对原来的对象进行retain
    
    NSString *str2 = [str copy];
    NSLog(@"str = %lu", [str retainCount]);
    
    [str release];
    [str release];
    
    //深拷贝:会生成新的对象,正是因为会生成新的对象,所以系统不会对以前的对象进行retain,但是因为生成了新的对象,所以我们需要对新的对象进行release
    NSMutableString *strM = [str mutableCopy];
    NSLog(@"str = %lu", [str retainCount]);
    NSLog(@"strM = %lu", [strM retainCount]);
    
    NSLog(@"%p - %p", str, strM);
    [strM release];
    [str release];

2.copy的第一个用途, 防止外界修改内部的数据

   NSMutableString *temp = [NSMutableString stringWithFormat:@"lnj"];
    
    Person *p = [[Person alloc] init];
    p.name = temp;
    
    // 问题: 修改了外面的变量, 影响到了对象中的属性
    [temp appendString:@" cool"];
    
    NSLog(@"name = %@", p.name);
    
    // 记住: 以后字符串属性都用copy

3.可以使用copy保存block, 这样可以保住block中使用的外界对象的命

    // block默认存储在栈中, 栈中的block访问到了外界的对象, 不会对对象进行retain
    // block如果在堆中, 如果在block中访问了外界的对象, 会对外界的对象进行一次retain
    Person *p = [[Person alloc] init];
    NSLog(@"retainCount = %lu", [p retainCount]);
    void (^myBlock)() = ^{
        NSLog(@"%@", p);
        NSLog(@"retainCount = %lu", [p retainCount]);
    };
    Block_copy(myBlock); // 将block转移到堆中
    myBlock();

4.copy block之后引发循环引用

#import "ViewController.h"
typedef void (^personBlock)();
@interface Person:NSObject
@property (nonatomic,copy)NSString *name;

@property (nonatomic,copy)personBlock pBlock;
@end
@implementation Person



@end
@interface ViewController ()
@property(nonatomic,copy)NSString *name;

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // 3.注意点: copy block之后引发循环引用
    // 如果对象中的block又用到了对象自己, 那么为了避免内存泄露, 应该将对象修饰为__block
    __block Person *p = [[Person alloc] init]; // 1
    p.name = @"lnj";
    NSLog(@"retainCount = %lu", [p retainCount]);
    p.pBlock = ^{
        NSLog(@"name = %@", p.name); // 2
    };
    
    p.pBlock();
    NSLog(@"retainCount = %lu", [p retainCount]);
    [p release]; // 1
    //    [p release]; // 2B
}

@end

5.自定义类实现copy

/*
     1.以后想让自定义的对象能够被copy只需要遵守NSCopying协议
     2.实现协议中的- (id)copyWithZone:(NSZone *)zone
     3.在- (id)copyWithZone:(NSZone *)zone方法中创建一个副本对象, 然后将当前对象的值赋值给副本对象即可
     */
  
    Person *p = [[Person alloc] init];
    p.age =  30;
    p.name = @"lnj";
    NSLog(@"%@", p);
//    Person *p2 = [p copy];
    Person *p2 = [p mutableCopy];
    
    NSLog(@"%@", p2);
- (id)copyWithZone:(NSZone *)zone
{
    // 1.创建一个新的对象
    Person *p = [[[self class] allocWithZone:zone] init];
    
    // 2.设置当前对象的内容给新的对象
    p.age = _age;
    p.name = _name;
    
    // 3.返回新的对象
    return p;
}
- (id)mutableCopyWithZone:(NSZone *)zone
{
    // 1.创建一个新的对象
    Person *p = [[[self class] allocWithZone:zone] init];
    
    // 2.设置当前对象的内容给新的对象
    p.age = _age;
    p.name = _name;
    
    // 3.返回新的对象
    return p;
}



   // 如果想让子类在copy的时候保留子类的属性, 那么必须重写copyWithZone方法, 在该方法中先调用父类创建副本设置值, 然后再设置子类特有的值 

- (id)copyWithZone:(NSZone *)zone
{
    // 1.创建副本
//    id obj = [[self class] allocWithZone:zone];
    id obj = [super copyWithZone:zone];
    // 2.设置数据给副本
//    [obj setAge:[self age]];
//    [obj setName:[self name]];
    [obj setHeight:_height];
    
    // 3.返回副本
    return obj;
}

6.ARC与MRC混合编程

Xcode 工程中我们可以使用 ARC 和MRC 的混合模式。
选中 Target, 在 Objective C language 地方,将 ARC 设为 YES 或 NO。 这是一个总开关。 如有特别的文件, 可以单独加上开关。

2860348713351508706.png

如何在未使用arc的工程中引入一个使用了arc特性的文件:
打开工程找到target -> Build Phases -> Compile Sources.

双击需要改模式的 代码对应的 .m 文件

在弹出窗口中输入上面提到的标签 -fobjc-arc (ARC模式) -fno-objc-arc(MRC模式)。

回车 保存 即可

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容