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模式)。

回车 保存 即可

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,830评论 5 468
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,992评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,875评论 0 331
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,837评论 1 271
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,734评论 5 360
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,091评论 1 277
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,550评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,217评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,368评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,298评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,350评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,027评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,623评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,706评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,940评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,349评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,936评论 2 341

推荐阅读更多精彩内容