iOS内存管理总结

一、详述OC的内存管理机制。

OC使用引用计数(retainCount)的机制来管理对象。自己生成的对象,自己持有。非自己生成的对象自己也能处理。不在需要自己持有的对象时,释放掉。非自己持有的对象无法释放。

a、在MRC中,retain与release配对使用,retain引用计数+1,release引用计数-1。
b、与alloc配对使用的方法是dealloc,alloc是开辟内存空间,dealloc是销毁开辟的内存空间。
c、readwrite、readonly读写控制。

readwrite即声明getter方法又声明setter方法。
readonly告诉编译器之生命getter方法。
默认属性为readwrite。

d、nonatomic,atomic为原子性控制

nonatomic非原子性控制,此时setter、getter方法不会做多线程处理,提高系统性能。
atomtic为原子性,此时setter、getter方法会做多线程处理,要不断的对setter、getter方法加锁解锁来保证线程安全,但是也降低了系统的性能。


属性关键字.png

二、delegate为什么用assign或者weak?详述!

a、delegate之所以使用weak来修饰

为了防止循环引用,weak属性的变量是不为其所属对象所持有,并且在该对象被销毁后,此weak变量的值会自动被赋值为nil。而assign属性一般是对C基本数据类型成员变量的声明,当然也可以用在对象成员变量上,只是其代表的意义只是单纯的拷贝所赋值变量的值。
场景:对某成员变量B赋值某对象A的指针,则B只是简单地保存此指针的值,并不持有对象A,那么如果A被销毁,B就会指向一个已经被销毁的对象,如果再对其发送消息会引起崩溃。

b、扩展空指针和野指针定义

空指针:没有存储任何内存地址的指针就称为空指针。如:NSString *str= nil/NULL;
野指针:指针指向一个已经被销毁的内存。
总结:使用野指针是非常危险的,容易引发崩溃。而使用空指针发消息是没有任何问题的。

c、总结

assign是指针赋值,不对引用计数操作,使用之后如果没有置为nil,可能就会产生野指针;而weak一旦不进行使用后,永远不会使用了,就不会产生野指针!


weak&assgin.png

三、Block的使用

a:为什么使用weakSelf?

因为Block是一个结构体,它会将一个全局变量保存为一个属性(__strong),而self强引用了Blcok这会造成循环引用,所以使用__weak修饰weakSelf。

b:为什么在Block里面使用strongSelf?

为了保证block在执行完毕之前self不会被释放,而strongSelf是为了保证Block内部执行的时候不会被释放,但是存在执行前就已经额比释放的情况,导致strongSelf=nil。注意判空处理,防止出现崩溃。typeof是编译时确定变量类型,所以这里写self 不会被循环引用。

c:总结:

外部使用了weakSelf,里面使用strongSelf却不会造成循环,究其原因就是因为weakSelf是block截获的属性,而strongSelf是一个局部变量会在“函数”执行完释放。

d:扩展:

__block可以让block修改局部变量,而__weak不能。
MRC中__block是不会引起retain;但在ARC中__block则会引起retain,因为,block也是一个强引用,引起循环引用,会引起循环引用。所以ARC中应该使用__weak。

    //1、无传参无返回值
    void (^PrintBlock)(void) = ^(){
        NSLog(@"-------没有传参也没有返回值");
    };
    PrintBlock();
    
    //2、有传参有返回值
    int mutiplier = 7;
    int(^backBlock)(int) = ^(int num){
        
        NSLog(@"有传参有返回值,传参为:%d",num);
        return mutiplier*num;
    };
    NSLog(@"调用传参有返回值的方法,返回值:%d",backBlock(2));

    //3、有传参没有返回值
    void(^numberBlcok)(int) = ^(int num){
        NSLog(@"传参为:%d",num);
        
    };
    numberBlcok(555);
    
    //4、修改外部变量
    __block int x = 110;
    void(^sumNumberBlock)(int) = ^(int y){
        x += y;
        NSLog(@"输出值为:%d",x);
    };
    sumNumberBlock(1);
####1、用SecondViewController的Block传参改变ViewController的值
  SecondViewController *vc = [[SecondViewController alloc] init];
    __weak typeof(self) weakSelf = self;
    vc.textViewBlock = ^(NSString *text){
        __strong typeof(weakSelf) strongSelf = weakSelf;
        
        strongSelf.label.text = text;
    };

####2、在SecondViewController的.h中声明,在.m文件中实现。
//声明Block的名字,确定参数类型 我们也可以使用strong来声明,最后内部处理还是为copy类型。
@property (nonatomic,copy)void (^textViewBlock)(NSString *text);
  self.textViewBlock(@"泰山旅游");
d、再扩展

那么我们可以思考下,在什么时候在Block中不需要使用weakSelf呢?下面是找的资料给出的解释,我在这里贴出来供大家参考。

当block本身不被self 持有,而被别的对象持有,同时不产生循环引用的时候,就不需要使用weakself了。最常见的代码就是UIView的动画代码,我们在使用UIView animateWithDuration:animations方法 做动画的时候,并不需要使用weakself,因为引用持有关系是:
UIView 的某个负责动画的对象持有block,block 持有了self因为 self 并不持有 block,所以就没有循环引用产生,因为就不需要使用 weak self 了。

[UIView animateWithDuration:0.2 animations:^{
    self.alpha = 1;
}];

当动画结束时,UIView会结束持有这个 block,如果没有别的对象持有block的话,block 对象就会释放掉,从而 block会释放掉对于 self 的持有。整个内存引用关系被解除。

拓荒者:
1.在block里使用strongSelf是防止在block执行过程中self被释放。 2.可以通过在执行完block代码后手动把block置为nil来打破引用循环,AFNetworking就是这样处理的,避免使用者不了解引用循环造成内存泄露。实际业务中暂时没遇到这种需求,请巧哥指点什么情况下会有这种需求。

陈祥龙:
strongSelf 一般是在为了避免 block 回调时 weak Self变成了nil ,异步执行一些操作时可能会出现这种情况,不知道我说得对不对。因业务需要不能使用weakSelf 这种情况还真没遇到过

e、为什么系统的block,AFN网络请求的block内使用self不会造成循环引用?
  • 解释一:
    其实只要抓住循环引用的本质,就不难理解。所谓循环引用,是因为当前控制器在引用着block,而block又引用着self即当前控制器,这样就造成了循环引用。系统的block或者AFN等block的调用并不在当前控制器中调用,那么这个self就不代表当前控制器,那自然也就没有循环引用的问题。以上引用均指强引用。
  • 解释二:
    UIView的动画block不会造成循环引用的原因就是,这是个类方法,当前控制器不可能强引用一个类,所以循环无法形成。而AFN无循环是因为绝大部分情况下,你的网络类对象是不会被当前控制器引用的,这时就不会形成引用环。当然我不知道AFN是否做了别的处理,按照这样来说的话,如果你的控制器强引用了这个网络类的对象,而且在block里面引用了当前控制器,也是会发生循环引用的。
    AFNetworking是因为人家大神自己封装了一个completionBlock,不管你传进来是啥,都会将Block值nill从而给你把循环引用打破。
    资料来源:https://www.zhihu.com/question/36358590

总结:通用情况 : 在block本身不被self持有,而被别的对象持有,同时不产生循环引用的时候,就不需要使用weakself了。

下面展示AFNetWorking中的completionBlock打断循环引用。

1、在AFHTTPRequestOperation.m中的SetCompletionBlock有提示说明:

// completionBlock is manually nilled out in AFURLConnectionOperation to break the retain cycle.
翻译大致意思就是,在AFURLConnectionOperation中置nil,打断循环引用。
调用completionBlock.png

2、在AFURLConnectionOperation.m中,我们看到completionBlock置nil的处理。


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

推荐阅读更多精彩内容