Objective-C 学习第六天

一、

  1. 内存管理
    内存的作用: 存储数据.
    1). 如何将数据存储到内存之中
    声明1个变量,将这个数据存储进去
    2). 当数据不再被使用的时候,占用的内存空间如何被释放

  2. 内存中的五大区域
    栈:局部变量,当局部变量的作用域被执行完毕之后,这个局部变量就会被系统立即回收.
    堆:OC对象,使用C函数申请的空间
    BSS段:未初始化的全局变量、静态变量,一旦初始化就回收,并转存到数据段中.
    数据段:已经初始化的全局变量、静态变量,知道程序结束的时候才会被回收.
    代码段:代码,程序结束的时候,系统会自动回收存储在代码段中的数据.

    栈、BSS段、数据段、代码段存储在它们中的数据的回收,是系统自动完成的.

  3. 分配在堆区的OC对象,是肯定需要被回收的.
    iPhone 内存机制,如果内存占用内存达到40M会受到系统警告,120M会闪退.

    存储在堆中的OC对象,系统是不会自动回收的,知道程序结束的时候才会被回收。

  4. 内存管理的范围:
    只需要管理堆中的OC对象的回收,其他区域中的数据是系统自动管理的.

  5. 对象应该什么时候被回收?
    当有人使用这个对象的时候,这个对象就不会被回收,只有在没有人使用的时候才可以被回收.

  6. 引用计数器
    1). 每一次对象都有一个属性,叫做retainCount(引用计数器),类型是unsigned long占据八个字节。
    引用计数器的作用: 用来记录这个对象有多少人在使用它,默认情况下,创建一个对象出来,这个引用计数器的默认值是1.
    2). 当多一个人使用的时候,这个引用计数器的值+1
    3). 当少一个人使用的时候,这个引用计数器的值-1
    4). 当这个对象的引用计数器变为0的时候,代表这个无人使用,系统就会自动回收它.

  7. 如何操作引用计数器
    1). 为对象发送1条retain消息,对象的引用计数器就会加1,当多一个人使用的对象的时候才发
    2). 为对象发送1条release消息,对象的引用计数器就会减1,当少一个人使用的对象的时候才发
    3). 为对象发送一条retainCount消息,就可以了取到对象的引用计数器的值
    4). 当对象的引用计数器变为0的时候,对象就会被系统立即回收, 在对象被回收的时候,会自动调用对象的dealloc方法.

  8. 内存管理的分类
    1).MRC(Manual Reference Counting)手动引用计数,手动内存管理.
    当多一个人使用对象的时候,要求程序员手动的发送retain消息;反之.
    2). ARC(Automatic Reference Counting)自动引用计数,自动内存管理.
    系统自动的在合适的地方发送retain realse消息.

    1. 学习MRC理由:面试、早期的App开发使用的是MRC技术、ARC是基于MRC的.

二、MRC

  1. Xcode默认的开发方式是ARC模式.
    关闭ARC:Project->选中工程->Build Settings-> All->Apple LLVM7.0 - Language - Objective C ->Objective-C Automatic Reference Counting,设置为NO.

  2. 当对象的引用计数器变为0的时候,系统会自动回收对象. 在系统回收对象的时候,会自动的调用对象的dealloc方法.
    1). 重写类的dealloc方法, 必须要调用父类的dealloc方法,要放在最后一句代码的位置。

        - (void)dealloc{
            NSLog(@"名字叫XXX消失了");
            [super dealloc];
        }
    
  3. 测试引用计数器
    1). 新创建一个对象,这个对象的引用计数器的值默认是1.

        Person *p1 = [[Person alloc] init];
        [p1 retainCount];// 获取引用计数器的值
        [p1 retain];//为引用计数器加1
        [p1 release];//为引用计数器减1
    

    2). 当对象的引用计数器变为0的时候,对象就会被系统立即回收,并自动调用dealloc方法.
    3). 为对象发送这个return消息,对象的引用计数器就会加1

  4. 为对象发送release消息并不是回收对象,而是让对象的引用计数器减1,当对象的引用计数器的值变为0的时候,对象才会被系统立即回收.

  5. 内存管理的重点
    1). 什么时候为对象发送retain消息
    当多一个人使用这个对象的时候,应该先为这个对象发送retain消息
    2). 什么时候为对象发送release消息
    当少一个人使用这个对象的时候,应该为这个对象发送一条release消息
    在ARC机制下,retain、release、dealloc这些方法无法调用

  6. 内存管理的原则
    1). 有对象的创建,就要匹配一个release
    2). retain和release的调用次数要匹配
    3). 谁用谁retain,谁不用谁release
    4). 只有在多一个人用的时候才retain,少一个人使用的时候才release,有始有终,有加就有减。

  7. 野指针
    C语言中的野指针: 定义一个指针变量,没有初始化,这个指针变量的值时一个垃圾值,指向一块随机的空间
    OC中的野指针:指针指向的对象已经被回收了.

  8. 内存回收的本质:
    申请一个变量,实际上就是向系统申请指定字节数的空间,这段空间就不会分配给别人了,当变量被回收的时候,代表变量占用的字节空间可以分配给别人了,但是这个字节空间中存储的数据还在。
    对象回收的本质:指的是对象占用的空间可以分配给别人了,当这个对象占用的空间没有分配给别人之前,其实对象数据还在.

  9. 僵尸对象
    1个已经被释放的对象,但是这个对象所占空间还没有分配给别人。通过野指针访问僵尸对象的时候,有可能没问题,也有可能有问题。当僵尸对象占用的空间还没有分配给别人使用的时候,还是可以的;反之。

  10. 我们认为只要对象成为了僵尸对象,无论如何都应该不允许访问了。如果访问的是僵尸对象,无论如何都报错。
    僵尸对象的实时检查机制,可以将这个机制打开,打开之后,只要访问的是僵尸对象,无论空间是否分配,就会报错。

    停止运行按钮右侧的Target切换点击-> Edit Scheme...->Run->Diagnostics->勾选Enable Zomble Objects.

  11. 为什么不默认打开僵尸对象检测
    一旦打开僵尸对象检测,那么在每访问一个僵尸对象的时候,都会先检测这个对象是否是一个僵尸对象,这样是极其消耗性能的.

  12. 如何避免僵尸对象错误?
    当一个指针成为野指针以后,将这个指针的值设置为nil.
    当一个指针为nil时,通过这个指针调用对象的方法的时候,不会报错,只是没有任何反应,但是如果通过指针直接访问属性就会报错.

  13. 无法复活一个僵尸对象

三、

  1. 内存泄漏
    指的是一个对象没有被及时的回收,在该回收的时候没有及时回收,一直驻留在内存中,知道程序结束的时候才结束.

  2. 单个对象的内存泄漏情况
    1). 有对象的创建,而没有对应的release
    2). retain的次数和release的次数不匹配
    3). 在不适当的时候为指针赋值为nil
    4). 在方法中为传入的参数不适当的retain

  3. 如何保证单个对象可以被回收
    1). 有对象的创建,就必须要匹配一个release
    2). retain和release次数一定要匹配
    3). 只有在指针成为野指针时才赋值为nil
    4). 在方法中不要随意的为传入的对象retain

  4. 多个对象的内存管理
    1). 当属性是一个OC对象的时候,setter方法的写法.
    将传进来的对象赋值给当前对象的属性,代表传入的对象多一个人使用,所以我们应该先为这个传入的对象发送一条retain消息再赋值.当当前对象销毁的时候,代表属性指向的对象少一个人使用,就应该在dealloc中release.
    代码写法:

        - (void)setCar:(Car *)car{
            _car = [car retain];
        }
    
        - (void)dealloc{
            [_car release];
            [super dealloc];
        }
    

    2). 当属性是一个OC对象的时候,setter方法按照上面写还是有bug.
    当为对象的这个属性多次赋值的时候,就会发生内存泄漏,发生泄漏的原因: 当为属性赋值的时候,代表就对象少一个人用,新对象多一个人用,应该release,旧对象retain新的.
    代码写法:

        - (void)setCar:(Car *)car{
            [_car release];
            _car = [car retain];
        }
    
        - (void)dealloc{
            [_car release];
            [super dealloc];
        }
    

    3). 出现僵尸对象的原因,新旧对象是同一个,当发现新旧对象是同一个的时候,什么都不用做.只有当新旧对象不是同一对象的时候,才release旧的.
    最终代码写法:

        - (void)setCar:(Car *)car{
            if(_car != car){
                [_car release];
                _car = [car retain];
            }
        }
    
        - (void)dealloc{
            [_car release];
            [super dealloc];
        }
    

    4). 特别注意: 内存管理的范围是OC对象,这个属性的setter方法才要像上面那样写.

  5. @property参数
    1). 作用
    a. 自动生成私有属性
    b. 自动生成这个属性的getter/setter的声明
    c. 自动生成这个属性的getter/setter的实现
    特别播报: 生成的setter方法实现中,无论什么类型,都是直接赋值.
    2). @property参数
    a. @property可以带参数
    @property(参数1, 参数2, 参数3...)数据类型 名称;
    b. @property的四组参数
    a). 与多线程相关的两个参数
    atomic/nonatomic
    b). 与生成的setter方法的实现相关的参数
    assign/retain
    c). 与生成只读、读写相关的参数
    readonly/readwrite
    d). 与生成getter/setter方法名相关的参数
    getter/setter

    3). 与多线程相关的参数(atomic/nonatomic)
    atomic: 默认值,这个时候生成的setter方法的代码就会被加上一把线程安全锁.特点: 安全、效率低
    nonatomic: 生成的setter方法的代码不会加线程安全锁,但是效率高.
    建议要效率,选择使用nonatomic
    4). 与生成的setter方法的实现相关的参数(assign/retain)
    assign: 默认值,生成的setter方法实现就是直接赋值
    retain: 生成的setter方法的方法实现就是标准的MRC内存管理代码,先判断新旧对象是否为同一对象,如果不是就release旧的,retain新的.
    当属性的类型是OC对象类型的时候就使用retain,当属性的类型实时非OC对象的时候就使用assign.
    注意: retain只是生成标准的setter方法为标准的MRC内存管理代码,不会自动的在dealloc中生成release的代码,需要手动添加.
    5). 与生成只读、读写相关的参数readonly/readwrite)
    readwrite: 默认值,代表同时生成getter/setter
    readonly: 只会生成getter,不会生成setter

    6). 与生成getter/setter方法名相关的参数(getter/setter)
    默认情况下: @property生成的getter/setter是标准类型的,其实我们可以通过参数来指定@property生成的方法的名字
    setter: setter=setter方法名字 用来指定@property生成的setter的方法的名字,注意,setter方法是带参数的,要加一个冒号
    getter: getter=getter方法名字 用来指定@property生成的getter方法的名字
    注意: 如果使用setter/getter修改了生成方法的名字,在使用点语法的时候,编译器在转换的时候转换成修改后的名字的代码.
    使用建议:
    a. 无论什么情况都不要改setter方法的名字,默认情况下生成的名字已经是最标准的了
    b. 什么修改getter方法的名字,当属性的类型是一个BOOL类型的时候,就修改这个getter的名字以is开头,提高代码的阅读性.

  6. @class
    1). 当两个类相互引用的时候,当Person.h中包含Book.h,而Book.h中又包含Person.h,这个时候就会造成无限递归,而导致无法编译通过.
    2). 解决方案:
    其中一个类中不要使用#import引入对方的头文件,而是使用@class 类名,来标注这是一个类,这样就可以在不引入对方头文件的情况下,告诉编译器这是一个类。
    在.m文件当中再#import对方的头文件
    3). @class与#import的区别
    a. #import是将指定的文件的内容拷贝到写指令的地方
    b. @class并不会拷贝任何内容,只是告诉编译器这是一个类,这样编译器在编译的时候才可以指定这是一个类。

  7. 循环retain
    1). 当两个对象相互引用的时候
    A对象的属性是B对象,B对象的属性是A对象.如果两边都使用retain,就会发生内存泄漏
    2). 解决方案
    一段使用retain,一段使用assign,使用assign的那一段在dealloc中不再需要release.

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

推荐阅读更多精彩内容

  • Objective-C 1. import的用法 拷贝文件内容可以自动防止文件的内容被重复拷贝(#define宏定...
    马文涛阅读 5,335评论 3 17
  • 内存管理是程序在运行时分配内存、使用内存,并在程序完成时释放内存的过程。在Objective-C中,也被看作是在众...
    蹲瓜阅读 3,054评论 1 8
  • OC基础总结 重新回过头看这些基础知识,对许多知识点都有新的认识,拥有坚实的基础才能更快的成长。 OC内存管理 -...
    xx_cc阅读 2,703评论 1 21
  • //--------------------内存管理 内存管理范围: 管理任何继承NSObject的对象,基本数据...
    指尖猿阅读 697评论 0 1
  • 第一天 一九四五年十二月二十五日 友子,太阳已经完全没入了海面 我真的已经完全看不见台湾岛了 你还站在那里等我吗?...
    旅行祈祷与爱阅读 3,346评论 0 1