博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Object-C——内存管理
阅读量:4317 次
发布时间:2019-06-06

本文共 4963 字,大约阅读时间需要 16 分钟。

 

一、计数器

   (一)、引用计数器的基本操作

        1、 方法的基本使用

          ①  retain :计数器+1,会返回对象本身
          ②  release :计数器-1,没有返回值
          ③  retainCount :获取当前的计数器
          ④ dealloc
             * 当一个对象要被回收的时候,就会调用
             * 一定要调用[super dealloc],这句调用要放在最后面

1 #import "Person.h" 2  3 @implementation Person 4  5  6 // 当一个Person对象被回收的时候,就会自动调用这个方法 7 - (void)dealloc 8 { 9     NSLog(@"Person对象被回收");10     11     // super的dealloc一定要调用,而且放在最后面12     [super dealloc];13 }14 15 @end

 

        2、 概念
         ①  僵尸对象 :所占用内存已经被回收的对象,僵尸对象不能再使用
         ②  野指针 :指向僵尸对象(不可用内存)的指针,给野指针发送消息会报错(EXC_BAD_ACCESS)
         ③  空指针 :没有指向任何东西的指针(存储的东西是nil、NULL、0),给空指针发送消息不会报错

          3、代码举例

1 #import 
2 #import "Person.h" 3 4 int main() 5 { 6 // 1 7 Person *p = [[Person alloc] init]; 8 9 //NSUInteger c = [p retainCount];10 11 //NSLog(@"计数器:%ld", c);12 13 14 // 2 retain方法返回的是对象本身15 [p retain];16 17 // 118 [p release];19 20 // 0 野指针:指向僵尸对象(不可用内存)的指针21 [p release];22 23 [p retain];24 25 // -[Person setAge:]: message sent to deallocated instance 0x100109a1026 // 给已经释放的对象发送了一条-setAge:消息:27 p.age = 10;28 //[p setAge:10];29 30 // 指针p变成空指针31 //p = nil;32 33 // EXC_BAD_ACCESS : 访问了一块坏的内存(已经被回收、已经不可用的内存34 // 野指针错误35 // OC不存在空指针错误,给空指针发送消息,不报错36 [p release];37 [p release];38 [p release];39 [p release];40 41 [nil release];42 43 return 0;44 }

(二) 多个对象之间的内存管理

       1、 你想使用(占用)某个对象,就应该让对象的计数器+1(让对象做一次retain操作)

       2、 你不想再使用(占用)某个对象,就应该让对象的计数器-1(让对象做一次release)
       3、 谁retain,谁release
       4、 谁alloc,谁release

1 // b-1 2     Book *b = [[Book alloc] init]; 3     // p-1 4     Person *p1 = [[Person alloc] init]; 5      6     //p1想占用b这本书 7     // b-2 8     [p1 setBook:b]; 9     10     // p-011     // b-112     [p1 release];13     p1 = nil;14     15     // b-016     [b release];17     b = nil;

 (三)、set方法的内存管理

    1、内存管理代码规范:

        ①  只要调用了alloc,必须有release(autorelease)
        ②  对象不是通过alloc产生的,就不需要release

    2、set方法

        ① 代码规范实现

1 //基本数据类型:直接复制 2  - (void)setAge:(int)age 3  {  4     _age = age; 5  } 6   7 // OC对象类型 8  - (void)setCar:(Car *)car 9  {10     // 1.先判断是不是新传进来对象11     if ( car != _car )12     {13         // 2.对旧对象做一次release14         [_car release];15  16         // 3.对新对象做一次retain17         _car = [car retain];18     }19  }

     3、dealloc方法的代码规范实现

1 //一定要[super dealloc],而且放到最后面2 // 对self(当前)所拥有的其他对象做一次release3  - (void)dealloc4  {5     [_car release];6     [super dealloc];7  }

  (四) @property参数

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

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

// retain : 生成的set方法里面,release旧值,retain新值@property (retain) Book *book;@property (retain) NSString *name;

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

@property ( assign) int height;

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

        2、控制生成或者不生成set方法

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

             *readonly  :只会生成get方法

@property (readwrite, assign) int height;

         3、多线程管理

             *atomic    :性能低(默认)

             *nonatomic :性能高

@property (nonatomic, assign, readwrite) int weight;

          4、控制set方法和get方法的名称

              *setter : 设置set方法的名称,一定有个冒号:

              *getter : 设置get方法的名称

// 返回BOOL类型的方法名一般以is开头@property (getter = isRich) BOOL rich;

  (五) 循环引用

       1、 @class

          ①  作用:仅仅告诉编译器,某个名称是一个类

          ②  开发中引用一个类的规范
            *在.h文件中用@class来声明类

1 #import 
2 #import "Card.h" 3 // @class仅仅是告诉编译器,Card是一个类 4 //@class Card; 5 6 @interface Person : NSObject 7 8 @property (nonatomic, retain) Card *card; 9 10 @end

 

            * 在.m文件中用#import来包含类的所有东西

1 #import "Person.h" 2 #import "Card.h" 3  4 @implementation Person 5  6 - (void)dealloc 7 { 8     NSLog(@"Person被销毁了"); 9     [_card release];10     11     [super dealloc];12 }13 14 @end

    2、循环retain

       ①问题

          *A对象retain了B对象,B对象retain了A对象

          *这样A、B对象永远无法释放

       ②两端循环引用解决方案

         * 一端用retain
         * 一端用assign          

  (六)、 autorelease

           1、autorelease的基本用法

              ①  会将对象放到一个自动释放池中
              ②  当自动释放池被销毁时,会对池子里面的所有对象做一次release操作
              ③  会返回对象本身
              ④  调用完autorelease方法后,对象的计数器不变
 
            2、autorelease的好处
              ①  不用再关心对象释放的时间
              ②  不用再关心什么时候调用release
 
           3、autorelease的使用注意
              ①  占用内存较大的对象不要随便使用autorelease
              ②  占用内存较小的对象使用autorelease,没有太大影响
           4、错误写法
              ①  alloc之后调用了autorelease,又调用release

1  @autoreleasepool2  {3     // 14     Person *p = [[[Person alloc] init] autorelease];5  6     // 07     [p release];8  }9

           ②  连续调用多次autorelease

1 @autoreleasepool2  {3     Person *p = [[[[Person alloc] init] autorelease] autorelease];4  }

          5、自动释放池

           ①  在iOS程序运行过程中,会创建无数个池子。这些池子都是以栈结构存在(先进后出)

           ②  当一个对象调用autorelease方法时,会将这个对象放到栈顶的释放池

           6、自动释放池的创建方式

@autoreleasepool {     }

          7、代码举例

1 void test() 2 { 3     @autoreleasepool 4     {
// { 开始代表创建了释放池 5 6 // autorelease方法会返回对象本身 7 // 调用完autorelease方法后,对象的计数器不变 8 // autorelease会将对象放到一个自动释放池中 9 // 当自动释放池被销毁时,会对池子里面的所有对象做一次release操作10 Person *p = [[[Person alloc] init] autorelease];11 12 p.age = 10;13 14 15 16 @autoreleasepool17 {18 // 119 Person *p2 = [[[Person alloc] init] autorelease];20 p2.age = 10;21 22 23 }24 25 26 Person *p3 = [[[Person alloc] init] autorelease];27 28 29 } // } 结束代表销毁释放池30 }

 

  

转载于:https://www.cnblogs.com/gaizuojia/p/4357563.html

你可能感兴趣的文章
日期转换为新数据类型CONVERT() 函数
查看>>
C#设计模式之十外观模式(Facade Pattern)【结构型】
查看>>
Redis进阶实践之十五 Redis-cli命令行工具使用详解第二部分(结束)
查看>>
Git使用gitignore建立项目过滤规则
查看>>
Can you solve this equation?
查看>>
经典算法50题
查看>>
广义距离变换
查看>>
2019年Q1总结+Q2大体规划
查看>>
struts2常用标签
查看>>
初次学习CentOS需要注意的问题
查看>>
初学C#之方法
查看>>
[Kubernetes]深入理解StatefulSet
查看>>
2018.2.2 java中的Date如何获取 年月日时分秒
查看>>
基础知识回顾:闭包
查看>>
luogu P1602 Sramoc问题
查看>>
11.29燃尽图
查看>>
CPU31X-2DP通过DP网络连接远程IO站
查看>>
Ubuntu 10.10更新源列表
查看>>
工作总结:文件对话框的分类(C++)
查看>>
Android log system
查看>>