自动内存管理(ARC)

news/2024/7/20 22:53:15 标签: IOS, 内存管理


/*

  1. 自动释放池的原理.

 

     存入到自动释放池中的对象,在自动释放池被销毁的时候.会自动调用存储在该自动释放池中的所有对象的release方法.

 

     可以解决的问题:

     将创建的对象,存入到自动释放池之中. 就不再需要手动的relase这个对象了.

     因为池子销毁的时候 就会自动的调用池中所有的对象的relase

 

 

  2. 如何创建自动释放池.

 

     @autoreleasepool

     {

 

     }

 

     这对大括弧代表这个自动释放池的范围.

 

  3. 如何将对象存储到自动释放池之中

    

     在自动释放池之中调用对象的autorelease方法.就会将这个对象存入到当前自动释放池之中.

 

     这个autorealse方法返回的是对象本身. 所以,我们可以这么写

       

     @autoreleasepool

     {

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

     }

 

     这个时候,当这个自动释放池执行完毕之后,就会立即为这个自动释放池中的对象发送1release消息.

 

     目前为止,我们感受到得autorelase的好处:

     创建对象,调用对象的autorelase方法 将这个对象存入到当前的自动释放池之中.

 

     我们就不需要再去relase 因为自动释放池销毁的时候 就会自动的调研池中所有对象的relase

 

  4. 使用注意

 

     1). 只有在自动释放池中调用了对象的autorelease方法,这个对象才会被存储到这个自动释放池之中.

         如果只是将对象的创建代码写在自动释放之中,而没有调用对象的autorelease方法.是不会将这个对象存储到这个自动释放池之中的.

 

     2). 对象的创建可以在自动释放池的外面,在自动释放池之中,调用对象的autorelease方法,就可以将这个对象存储到这个自动释放池之中.

 

     3). 如果对象的autorelease方法的调用放在自动释放池的外面,是无法将其存储的这个自动释放池之中的.

         autorelease 的调用只有放在自动释放池之中 才可以讲其存储到自动释放池之中,对象的创建可以在外面

 

 

     4). 当自动释放池结束的时候.仅仅是对存储在自动释放池中的对象发送1release消息 而不是销毁对象.

 

     5). 如果在自动释放池中,调用同1个对象的autorelease方法多次.就会将对象存储多次到自动释放池之中.

         在自动释放池结束的时候.会为对象发送多条release消息.

         所以,1个自动释放池之中,autorelease1,只将这个对象放1, 否则就会出现野指针错误.

 

     6). 如果在自动释放池中,调用了存储到自动释放中的对象的release方法.

         在自动释放池结束的时候,还会再调用对象的release方法.

         这个时候就有有可能会造成野指针操作.

 

     7). 将对象存储到自动释放池,并不会使对象的引用计数器+1 所以其好处就是:创建对象将对象存储在自动释放池,就不需要在写个release.

 

     8). 自动释放池可以嵌套.

          调用对象的autorelease方法,会讲对象加入到当前自动释放池之中

          只有在当前自动释放池结束的时候才会像对象发送release消息.

 

 5. autorelease的应用场景.

     0). 创建对象,将对象存储到自动释放池之中. 就不需要再去手动的realse

 

   

     1). 我们一般情况下,会为我们的类写1个类方法,用来让外界调用类方法来快速的得到1个对象.

         规范:使用类方法得到的对象,要求这个对象就已经被autorelease过了.

       

         提供1个类方法来快速的得到1个对象.

         规范

         a. 这个类方法以类名开头. 如果没有参数就直接是类名 如果有参数就是 类名WithXX:

         b. 使用类方法得到的对象,要求这个对象就已经被autorelease过了.

 

         + (Person *)person

         {

            return [[[Person alloc] init]autorelease];

         }

 

         这样,我们直接调用类方法.就可以得到1个已经被autorelease过的对象.

         @autoreleasepool

         {

             Person *p1 = [Person person];

             //这个p1对象已经被autorelase过了.不需要再调用autorelase

             //这个p1对象就被存储到当前自动释放池之中.

         }//当自动释放池结束.就会为存储在其中的p1对象发送release消息.

 

 

     2). 完善类方法.

         Person拥有1个子类Student. 这个Student子类也继承了父类的person类方法.

         但是.通过子类Student调用person类方法能创建1个子类Student对象吗?

         答案是否定的,因为person方法写死了,我们返回的就是1Person对象.

 

         我们的需求:

         通过父类Person调用这个类方法,返回的是Person对象,通过子类Student调用这个person类方法返回的是Student对象.

         a. 类方法person的返回值肯定不能写Person *.我们首先想到了使用万能指针id.

         b. 类方法的内部代码:  

            return [[[Person alloc] init]autorelease];

            就不能这样写了,因为这样仍然是创建Person对象.

 

            改成.

            return [[[self alloc] init]autorelease];

            在类方法中self代表当前类.通过那1个类调用这个方法self就是指的那1个类.

            所以,这个时候,通过Person类调用person方法 self就指Person.创建的就是Person对象.

            通过Student来调用person方法,self就指Student 创建的就是Student对象.

            多爽啊!

 

         代码改成如下:

         + (id)person

         {

            return [[[self alloc] init]autorelease];

         }

 

         这样貌似就可以了 完美.

 

     3). 继续完善类方法.

 

         上面写的方法,其实已经可以实现我们的需求了.

         但是存在1个小瑕疵.

       

         类方法person返回的类型是1id类型.

         id类型是1个无类型的指针. 其优点在于可以指向任何对象,编译器都不会报错.并且编译器不会做编译检查.

 

         所以,我们在创建对象的时候:

         Person *p1 = [Personperson]; 这样是没有问题的 因为创建的是Person对象 赋值给1Person指针.

         Student *s1 =[Student person]; 这样也是没有问题 因为创建的是Student对象,赋值给1Student指针.

 

         但是,各位,下面这样写:

         NSString *str = [Person person];

         你会发现这样是不出错的.编译器根本都不会警告.实际也是可以运行的.

         原因在于person类方法返回的是1个无类型的指针.

 

         所以这样明显是不允许的,但是编译器却步报错,甚至警告都不报.

         为了解决这个问题. 方法的返回值我们使用instancetype

 

         instancetype 只能作为方法的返回值.代表返回的是当前类的对象.

         这是1个有类型的指针.

         所以 当你将其赋值给1个类型不同的指针变量时 编译器就会报警告.

       

         + (instancetype)person

         {

            return [[[self alloc] init]autorelease];

         }

 

 6. 实际上Apple的框架中的类也是遵守这个规范的.

 

    通过类方法创建的对象都是已经被autorelease过的了.

 

    所以,我们也要遵守这个规范. 类方法返回的对象也要被autorealse.

 

    以后,我们凡事创建对象是调用类方法创建的对象 这个对象已经是被autorelease过的了.

 

 

 */

 

/*

 

 1. 什么是ARC

   

    Automatic ReferenceCounting,自动引用计数. ARC.

    顾名思义:系统自动的帮助我们去计算对象的引用计数器的值,

 

    可以说是WWDC2011iOS5引入的最大的变革和最激动人心的变化.

    ARC是新的LLVM3.0编译器的一项特性,使用ARC,可以说一举解决了广大iOS开着所憎恨的手动管理内存的麻烦.

 

    在程序中使用ARC非常简单,只需要像往常那样编写代码.

    只不过永远不要写retainreleaseautorelease这三个关键字就好,这是ARC的最基本的原则.

    ARC开启时, 编译器会自动的在合适的地方插入retainreleaseautorelase代码.

    编译器自动为对象做引用计数. 而作为开发者,完全不需要担心编译器会做错(除非开发者自己错用了ARC).

 

    需要特别注意的是: ARC是编译器机制. 在编译器编译代码的时候,会在适时的位置加入retainreleaseautorealse代码.

 

 2. ARC机制下,对象何时被释放

 

    只要没有强指针指向这个对象,这个对象就会立即回收.

 

 3. 强指针与弱指针.

 

    强指针: 默认情况下,我们声明1个指针 这个指针就是1个强指针.

           我们也可以使用__strong来显示的声明这是1个强指针.

           

           Person *p1; 这是1个强指针. 指针默认情况下都是1个强指针.

           __strong Person*p2; 这也是1个强指针.使用__strong来显示的声明强指针.

 

    弱指针: 使用__weak标识的指针就叫做弱指针.

 

          

    无论是强指针还是弱指针,都是指针,都可以用来存储地址,1点没有任何区别

    都可以通过这个指针访问对象的成员.

    唯一的区别就是在ARC模式下.他们用来作为回收对象的基准.

   

    如果1个对象没有任何强类型的指针指向这个对象的时候,对象就会被自动释放

 

 4. 确认程序是否开启ARC机制.

 

    1).默认情况下,Xcode开启ARC机制.

    2).ARC机制下,不允许调用retainrelaseretainCountautorelease方法.

    3).dealloc 不允许[superdealloc];

 

 

 5.  演示第1ARC案例

     int main(int argc, const char * argv[])

        {

            @autoreleasepool

            {

               Person *p1 = [Person new];//p11个强指针.

               //因为我们说过,1个指针变量默认情况下都是1个强指针变量.

               NSLog(@"------");

            }//当执行到这里的时候.p1指针被回收,那么Person对象就没有任何

            //强指针指向它了. 对象就在这被回收.

            return 0;

     }

 

 6. ARC下的单个对象的内存管理.

 

    1). 当指向对象的所有的强指针被回收的时候,对象就会被立即回收.

 

     int main(int argc, const char * argv[])

     {

         @autoreleasepool

         {

            Person *p1 = [Person new];//p11个强指针.

             Person *p2 =p1;//p2也是个强指针.p1p2都指向Person对象.

            //因为我们说过,1个指针变量默认情况下都是1个强指针变量.

            NSLog(@"------");

         }//当执行到这里的时候.p1指针被回收,p2指针也被回收.那么Person对象就没有任何

         //强指针指向它了. 对象就在这被回收.

         return 0;

     }

 

    2).将所有指向对象的强指针赋值为nil的时候.对象就会被立即回收.

       

     int main(int argc, const char * argv[])

     {

         @autoreleasepool

         {

            Person *p1 = [Person new];//p11个强指针.

            //因为我们说过,1个指针变量默认情况下都是1个强指针变量.

             

            p1 = nil;//当执行到这句话的时候.p1赋值为nil.

            //p1指针不再执行Person对象.

            //Person对象没有被任何的指针所指向,所以.Person对象在这里被释放.

            NSLog(@"------");

         }

         return 0;

     }

 

 

 

 7. 强指针与弱指针.

   

    1). 强指针与弱指针的声明.

 

    p1指针是强类型的,因为默认情况下指针都是强类型的.

    Person*p1 = [[Person alloc] init];

    不过我们可以使用__strong来显示的标识指针是强类型指针.

   __strong Person *p2 = [Person new];

    这个时候p2指针类型是强指针类型的.其实写不写__strong都是强类型的指针.

       

    指针类型也可以是弱指针类型.

    使用__weak标识指针的类型是弱类型指针.

    __weakPerson *p3 = p2;

    这个时候,p3指针就是1个弱类型的指针. p3弱指针也指向p2指针指向的对象.

 

    在操作对象的时候,通过强指针或者弱指针都可以操作,没有任何区别.

 

    2). ARC的对象回收标准

 

    ARC机制下释放1个对象的标准是: 没有任何强指针指向对象的时候,对象就会被释放.

    如果这个时候有弱指针指向,也会被释放.

    int main(int argc, const char * argv[])

    {

            @autoreleasepool

            {

               //使用__strong来标识p1指针是强类型的,其实不写__strong也是强类型的.

                __strongPerson *p1 = [[Person alloc] init];

                

               //使用__weak标识指针p2的类型是弱类型指针.

                __weakPerson *p2 = p1;

               //这个时候,p2指针和p1指针都指向Person对象.

                

               //这个时候如果设置p1的值为nil

                p1 = nil;

               //这个时候Person对象只有被1个弱指针p2指向,没有任何强指针指向

               //所以Person对象在这里被回收.

            }

            return 0;

     }

 

 

     3).最重要的1:不能创建对象用1个弱指针存储这个对象的指针.

        这样的话,刚创建出来的对象,就没有任何强指针指向,创建出来就会被回收.

     int main(int argc, const char * argv[])

     {

            @autoreleasepool

            {

               //创建1个对象,将这个对象的地址赋值给1个弱指针

               //后果就是创建出来的这个对象没有被任何强指针指向.

               //刚创建出来就会被释放.

                __weakPerson *p1 = [[Person alloc] init];

                

            }

            return 0;

     }

 

 

 

 */

 

 

/*

 1. ARC下的单个对象的内存管理.

 

     1). 当指向对象的所有的强指针被回收的时候,对象就会被立即回收.

 

     int main(int argc, const char * argv[])

     {

         @autoreleasepool

         {

           Person *p1 = [Person new];//p11个强指针.

            Person *p2 =p1;//p2也是个强指针.p1p2都指向Person对象.

           //因为我们说过,1个指针变量默认情况下都是1个强指针变量.

            NSLog(@"------");

         }//当执行到这里的时候.p1指针被回收,p2指针也被回收.那么Person对象就没有任何

         //强指针指向它了. 对象就在这被回收.

         return 0;

     }

 

     2).将所有指向对象的强指针赋值为nil的时候.对象就会被立即回收.

    

     int main(int argc, const char * argv[])

     {

         @autoreleasepool

         {

            Person *p1 = [Person new];//p11个强指针.

            //因为我们说过,1个指针变量默认情况下都是1个强指针变量.

             

            p1 = nil;//当执行到这句话的时候.p1赋值为nil.

            //p1指针不再执行Person对象.

            //Person对象没有被任何的指针所指向,所以.Person对象在这里被释放.

            NSLog(@"------");

         }

         return 0;

     }

 

 

 

 7. 强指针与弱指针.

    

    1). 强指针与弱指针的声明.

   

      默认情况下,所有的指针都是强类型的,也就是说我们之前声明的指针变量都是强类类型的

 

     p1指针是强类型的,因为默认情况下指针都是强类型的.

     Person *p1 = [[Person alloc]init];

 

     不过我们可以使用__strong来显示的标识指针是强类型指针.

     __strong Person *p2 = [Personnew];

     这个时候p2指针类型是强指针类型的.其实写不写__strong都是强类型的指针.

         

     指针类型也可以是弱指针类型.

     使用__weak标识指针的类型是弱类型指针.

     __weak Person *p3 = p2;

     这个时候,p3指针就是1个弱类型的指针. p3弱指针也指向p2指针指向的对象.

 

    在操作对象的时候,通过强指针或者弱指针都可以操作,没有任何区别.

    在操作对象的时候 通过强指针或者是弱指针都可以操作.

 

    2). ARC模式下的对象回收标准

 

     ARC机制下释放1个对象的标准是: 没有任何强指针指向对象的时候,对象就会被释放.

     如果这个时候有弱指针指向,也会被释放.

     int main(int argc, const char * argv[])

     {

         @autoreleasepool

         {

            //使用__strong来标识p1指针是强类型的,其实不写__strong也是强类型的.

             __strongPerson *p1 = [[Person alloc] init];

             

            //使用__weak标识指针p2的类型是弱类型指针.

             __weak Person*p2 = p1;

            //这个时候,p2指针和p1指针都指向Person对象.

             

            //这个时候如果设置p1的值为nil

             p1 = nil;

            //这个时候Person对象只有被1个弱指针p2指向,没有任何强指针指向

            //所以Person对象在这里被回收.

         }

         return 0;

     }

 

 

     3).最重要的1:不能创建对象用1个弱指针存储这个对象的指针.

     这样的话,刚创建出来的对象,就没有任何强指针指向,创建出来就会被回收.

     int main(int argc, const char * argv[])

     {

         @autoreleasepool

         {

            //创建1个对象,将这个对象的地址赋值给1个弱指针

            //后果就是创建出来的这个对象没有被任何强指针指向.

            //刚创建出来就会被释放.

             __weak Person*p1 = [[Person alloc] init];

             

         }

         return 0;

     }

 

 

 

 

 

 */

 

 

 

/*

 

  0. ARC机制下,set方法的封装不需要retainrelase

     直接赋值就可以了.

 

 

 

  1. 当对象的属性是另外1个属性的时候,这个属性应该是1个强指针还是弱指针?

 

     肯定需要是1个强指针.

     1个强指针指向1个对象的时候.

     说明我在用这个对象,这个对象就不能被销毁.

 

     当我被销毁的时候 我的强指针也被销毁了 说明我现在不用你了.

     对象再判断是否还有其他强指针指向它.以决定是否回收.

 

 

 

     说那么多的废话.

     只有1个结论.ARC机制下,如果1个对象的属性是1OC对象类型的 这个属性应该声明为1个强指针.

 

 

  2. 需要注意的是.如果对象没有被任何强指针指向.那么对象就会被回收.

     原来指向对象的弱指针的值会自动设置为nil

 

 

 

 

 

  3. 使用@property如何让生产的属性是1个强类型或者弱类型.

 

     使用参数. strongweak

 

     //@property参数strong 代表生成的私有属性_dog指针是1个强类型的指针.

 @property(nonatomic,strong)Dog *dog;

 

 //@property参数weak 代表生成的私有属性_name指针是1个弱类型的指针.

 @property(nonatomic,weak)NSString *name;

 

     默认的参数是strong

 

 

  4. @property参数注意.

 

     1).ARC机制下.@property参数retain就无法再使用了.因为retain参数代表的意义是生成的set方法是标准的MRC下的内存管理代码.

        ARC,不需要引用记数. 就不需要生成这些内存管理代码了.

 

     2).ARC机制下,属性的类型是OC对象类型的时候,一般使用strong. OC对象的类型使用assign

    

     3).strongweak都是针对OC对象类型的属性,OC对象不能使用strongweak

 

 

 

 

 

 

 

 */

 

 

/*

 

  1. 当两个类相互引用作为对方的属性的时候.

     ARC机制下. 如果两边的@property都是以strong 就会出现循环引用而导致的内存泄露

 

 

  2. 解决方案:

     一端使用strong 一端使用weak

 

 

 

 

 */

 

/*

 

  1. 程序的内存管理模式.分为两种. MRCARC

 

    

  2. 与多线程相关的参数.

 

     atomic: 默认值

     nonatomic

 

     无论是在ARC还是MRC模式下,都使用nonatomic

 

  3. retain: 只能使用在MRC模式下. 当属性的类型是1OC对象的时候,除了循环引用之外,全部都是使用retain

 

     assign: 既可以用在MRC,也可以用在ARC之中,

             MRC模式中和ARC模式下. 当属性的类型是1个非OC对象类型的时候. 使用assign

 

     MRC模式下,如果出现循环引用. 一端使用retain 一端使用assign

 

 

 

   4. strong: 只能使用在ARC模式下,当属性的类型是1OC对象的时候,除了循环引用之外,全部都是使用strong

      weak: 只能使用在ARC模式下,当出现循环引用的时候. 一端使用strong 一端使用weak

 

 

   5. readwrite: 可以使用在ARC模式和MRC模式下,代表同时生成属性的gettersetter

      readonly: 可以使用在ARC模式和MRC模式下 代表只成属性的getter

 

 

   6. 修改生成的getter setter的名字: ARCMRC中都可以使用.

 

 

 ---------------------

 

 @property参数: MRC中使用retain strong来代替就可以了.

 

 

 

 

 

 */

 

 

/*

  1 想象这样1个画面:

   

 

    你要使用别人的类,但是别人的类是在MRC模式下得. 而你的程序是ARC模式.

 

 

  2. ARC的程序中,有一些类使用MRC实现的.

 

     如果希望某些指定的类还是使用MRC. 那么这个时候可以在

     点击项目 -> 选中要改的Targer -> Bulid Phases -> ComplileSource

 

     在这里双击要修改模式的类.

     输入: -fno-objc-arc

 

     就代表这个类使用的是MRC

 

 

 

 

 */

 

/*

 

  转换的方式非常简单和粗暴:

 

    就是简单的替换:

       删除所有的 retain relase autorease [super dealloc]; retain strong

 

 

   所以是有可能会出错得.

 

 

 

 

 */


http://www.niftyadmin.cn/n/589287.html

相关文章

“三个月就是一年”——程序员的时间观念

这句话被程序员间传了很多年了,今天看到,记录下来,且行

servlet研究学习总结--OutputStream和PrintWriter的区别

当用户和浏览器其进行交互时,会给服务器发送http请求,Web服务器收到客户端的http请求,会针对每一次请求,分别创建一个用于代表请求的request对象、和代表响应的response对象。request和response对象即然代表请求和响应&#xff0c…

IOS中的Block的使用

/* 0. block 在iOS开发中 大量 频繁的使用到. 1. 我们说,OC在C的基础之上新增了一些数据类型. BOOL Boolean id class SEL nil block 除了block类型.其他的类型我们都全部讲过了. 2. block是个数据类型. int float double..... 都是用来声明变量 用这个变量来存储数据. int fl…

android 绘制折线图(AChartEngine)Linechart静态的

转自:http://hi.baidu.com/yurenmeiguis/item/4b9218df1a9ef5122b35c7bd 参考:http://www.cnblogs.com/youxilua/archive/2012/01/18/2325132.html 1、 使用Android 绘图工具库 AChartEngine 2、 绘制折线图的代码解析 关于工具库AChartEngine是为 an…

Android studio异常关闭导致build缓存出现问题

https://blog.csdn.net/u013164584/article/details/78531158

linux给文件授权

文件权限分为 :读,写,可执行 每个文件分为三种用户:主用户,同组用户,其它系统用户 用10位来表示:drwxr-xr-x 第一位代表文件类型 - 代表普通文件 d 代表目录 其余每三位代表一种用户的权限 …

File format not recognized

android studio编译卡死,强制重启电脑后报这个错误。 解决方案:删除上次生成的文件,重新编译。

2009 年度最佳 jQuery 插件

jQuery 是个宝库,而 jQuery 的插件体系是个取之不竭的宝库,众多开发者在 jQuery 框架下,设计了数不清的插件,jQuery 的特长是网页效果,因此,它的插件库也多与 UI 有关。本文是 webdesignledger.com 网站推选…