黑马程序员--IOS学习笔记(Object—C)内存管理

来源:互联网 发布:建表sql语句 编辑:程序博客网 时间:2024/04/28 23:59

---------------------- <a href="http://www.itheima.com"target="blank">iOS开发</a>、期待与您交流! ----------------------

笔记总结:

       一、基本原理

        1.  什么是内存管理

       * 移动设备的内存极其有限,每个app所能占用的内存是有限制的

       * 当app所占用的内存较多时,系统会发出内存警告,这时得回收一些不需要再使用的内存空间。比如回收一些不需要使用的对象、变量等

       * 管理范围:任何继承了NSObject的对象,对其他基本数据类型(int、char、float、double、struct、enum等)无效

         2.  对象的基本结构

         

      * 每个OC对象都有自己的引用计数器,是一个整数,表示“对象被引用的次数”,即有多少人正在使用这个OC对象

      * 每个OC对象内部专门有4个字节的存储空间来存储引用计数器

          3.  引用计数器的作用

      * 当使用allocnew或者copy创建一个新对象时,新对象的引用计数器默认就是1

      * 当一个对象的引用计数器值为0时,对象占用的内存就会被系统回收。换句话说,如果对象的计数器不为0,那么在整个程序运行过程,它占用的内存就不可能被回收,除非整个程序已经退出

          4. 引用计数器的操作

      *  给对象发送一条retain消息,可以使引用计数器值+1(retain方法返回对象本身)

      * 给对象发送一条release消息,可以使引用计数器值-1

      *  可以给对象发送retainCount消息获得当前的引用计数器值

         5. 对象的销毁

      *  当一个对象的引用计数器值为0时,那么它将被销毁,其占用的内存被系统回收

      *  当一个对象被销毁时,系统会自动向对象发送一条dealloc消息

      *  一般会重写dealloc方法,在这里释放相关资源,dealloc就像对象的遗言

      *  一旦重写了dealloc方法,就必须调用[super dealloc],并且放在最后面调用

      *  不要直接调用dealloc方法

      *  一旦对象被回收了,它占用的内存就不再可用,坚持使用会导致程序崩溃(野指针错误)


***笔记(基本理论)***

      retain 返回对象本身  比如:

      Person *p = [[Person alloc] init];       // retainCount为1,p是在栈内存中,其内保存着指向堆内存中开创出来的Person对象地址的值。

      [p retain];    // 返回本身     亦可表示成    p = [p retain]  // retainCount为2

      [p release];   // 计数器减1    retainCount 为1

      [p release]; // 计数器再减1retainCount 为0 ,将自动调用person对象的 dealloc方法,释放内存。注意,此时,p 中仍然保存着person对象的地址值,但此时,联系已经断开了,堆内存中的person对象已经消除了,称为僵尸对象!p此时也称为野指针!

      p.age = 5; // 注意,此处等于调用僵尸对象赋值,可能会不报错。在Xcode中开启内存管理开关(僵尸对象检查机制),就会报错。打开方法:Editschema --> Diagnostics -->Objective-c Enable Zombie Objects 上打钩

      [p release]; // 此时会报错。野指针指向的僵尸对象没法release;

      p = nil; // 将 p 这个野指针清空,此时称为 空指针

      [p release]; // 此处无错,空指针指向空对象可以release

       二、set方法内存管理

      如果你有个OC对象类型的成员变量,就必须管理这个成员变量的内存。比如有个Book *_book

        1.  set方法的实现

    - (void)setBook:(Book *)book{

        if (book !=_book) {

            [_bookrelease];

            _book= [book retain];

       }

    }

           2. dealloc 方法的实现

   - (void)dealloc {

            [_book release];

            [super dealloc];

   }

         三、@property参数

        1. 控制set方法的内存管理

         * retain: release旧值,retain新值(用于OC对象)

         * assign : 直接赋值,不做任何内存管理(默认,用于非OC对象类型)

         * copy   : release旧值,copy新值(一般用于NSString *)

        2. 控制需不需生成set方法

         * readwrite :同时生成set方法和get方法(默认)

         * readonly  :只会生成get方法

        3. 多线程管理     

         * nonatomic 非多线程 性能高

         * atomic 多线程  性能低 注意,默认是atomic的

           示例:

          @property(nonatomic,retain) NSString * name;

          @property(nonatomic,assign) int age;

         四、循环引用问题

                  即:A类中有一个属性是B对象,B类中有一个属性是A对象。这种情况在使用过程中,是会报错的。解决方法如下:

           在一个类中用assign声明属性,另一个类中用retain声明属性即可

                     额外说明:在.h文件中,用 @class 方式声明一个欲使用的类,在.m文件中再用#import引用类 (如有用到该类方法需导入此类时)

         五、autorelease

            * 给某个对象发送一条autorelease消息时,就会将这个对象加到一个自动释放池中

          * 当自动释放池销毁时,会给池子里面的所有对象发送一条release消息

          * 调用autorelease方法时并不会改变对象的计数器,并且会返回对象本身

          * autorelease实际上只是把对release的调用延迟了,对于每一次autorelease,系统只是把该对象放入了当前的autoreleasepool中,当该pool被释放时,该pool中的所有对象会被调用Release


            使用了autorelease,就不必再顾虑对象在何处release了,对象会被扔到自动释放池里,工作完了会自动release池子里的对象。autorelease返回对象本身。

       注意:

            1> 使用了autorelease,对象的引用计数并不会变化。

            2> 占用内存较大的对象,不要随便使用autorelease,因为他会一直占用着内存,等待自动释放池销毁。反之,占用内存较小的对象,使用autorelease则没有多大影响。

            3> autorelease错误写法1:

            @autorelease{

            Person *p = [[[Person alloc] init] autorelease];  // 计数器为 1

                 [p release]; // 计数器为0 此时p为野指针

             } // 自动释放池在此行销毁,会再次release一次其内的对象,也即再一次[prelease],而此时p是野指针了,所以会报错

                  错误写法2:

            @autorelease{

            Person *p =[[[[Person alloc] init] autorelease]autorelease];  

             }// 连续多次调用autorelease等效于自动释放池一销毁,会多次调用release,会引发野指针调用错误。

              autorelease实用技巧:

              若每次创建对象,都如此这般 Person * p = [[[Person alloc] init] autorelease]; 会显得很繁琐,尤其是多次创建对象。此时,可以在类中建立一个静态方法,示例如下:

             +(id) person{  return [[[self alloc] init ] autorelease]; }

              这样,每次创建对象的时候,只要 Person * p = [Person person];即可。

              注意,这里用self而不是Person是有讲究的,原因是考虑到Person的子类情况。例如,GoodPerson继承 Person类,如果此处不用self,而用Person,那么GoodPerson *gp = [GoodPerson person];实际返回的还是Person对象,这样子类中的一些方法就无法使用了。

           六、ARC

         ARC的判断准则:只要没有强指针指向对象,就会释放对象。

        指针分两种:

         1>  强指针,默认情况下,所有指针都是强指针 __strong

         2>  弱指针,__weak  使用示例:

                  __weak Person * p = [[Personalloc] init];

         手动管理内存到ARC的等效转变

        @propery(nonatomic,retain)  ----->@property(nonatomic,strong) 适用于OC对象

---------------------- <a href="http://www.itheima.com"target="blank">iOS开发</a>、期待与您交流! ----------------------

0 0
原创粉丝点击