笔记总结:

       一、基本原理

        1.  什么是内存管理

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

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

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

         2.  对象的基本结构

         

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

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

          3.  引用计数器的作用

alloc、new或者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
            [_bookrelease];
            _book= [book retain];
       }
    }


           2. dealloc 方法的实现


void)dealloc {
            [_book release];
super
   }


         三、@property参数

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

 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]; 会显得很繁琐,尤其是多次创建对象。此时,可以在类中建立一个静态方法,示例如下:

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对象