第三讲:Obj-C 内存管理1 - 黄金法则

来源:互联网 发布:巴比馒头 知乎 编辑:程序博客网 时间:2024/05/07 00:39

转:http://tigercat1977.blog.163.com/blog/static/2141561122012111293337435/

第三讲:Obj-C 内存管理1 - 黄金法则 

 
主要内容
      OC内存管理原理
      OC内存管理相对 C/C++ 有何好处
      OC内存管理的 alloc, retain, release
      遛狗原则
      OC 对象生命周期

内存管理  黄金法则
      The basic rule to apply is Everything that increases the refernce counter with alloc,
[mutable] copy [Whith Zone:] or retain is charge of the corresponding [auto] release.

      如果对一个对象使用了  alloc, [mutable] copy, retain, 
那么你必须使用相应的 release 或者 autorelease


内存管理类型定义

     基本类型   任何 C 的类型,如:
     int,  short,  char,  long,  long long,  struct,  enum,  union 等属于基本类型或者结构体
     内存管理对于 C 语言基本类型无效

     OC类型 (非基本类型)
     任何继承于 NSObject 类的对象都属于 OC 类型
     也就是除了 C 之外的其他类型

OC 对象结构
第三讲:Obj-C 内存管理1 - 黄金法则 - tigercat1977 - tiger notes

C / C++ 内存管理原理
第三讲:Obj-C 内存管理1 - 黄金法则 - tigercat1977 - tiger notes

C / C++ 内存管理代码
      Int *p1 = malloc(100);
      Int *p2 = p1;
      Int *p3 = p1;
      Free(p2);

      Free(p2);

内存管理对象
      对于OC的对象,非基本对象(int,  short, struct)
      NSObject, 凡是继承于 NSObject
      每一个对象都有一个 retainCount 计数器。表示当前的被应用的计数器。如果计数为0,那么就真正的释放这个对象

内存管理图示
      这就是引用计数的理论。在实际应用中,通过只有两个原因我们才会创建一个对象:
          1. 作为一个实例变量保留。
          2. 在函数内部作为临时变量使用。
      大多数情况下,一个实例变量的设置器(setter)会自动释放(autorelease)
      原来引用的对象,同时保留(retain)新的。你只需要保证在 dealloc 函数中释放(release)了它就行了。
第三讲:Obj-C 内存管理1 - 黄金法则 - tigercat1977 - tiger notes

遛狗原理
第三讲:Obj-C 内存管理1 - 黄金法则 - tigercat1977 - tiger notes

OC内存管理
第三讲:Obj-C 内存管理1 - 黄金法则 - tigercat1977 - tiger notes

alloc retain release 函数
      alloc 函数是创建对象使用,创建完成后计数器为 1
      只用一次

      retain 是对一个对象的计数器 +1
      可以调用多次

      release 是对一个对象计数器 -1
      减到 0 对象就会从内存中释放

OC内存管理
      Objective - C 类中实现了引用计数器,对象知道当前被引用了次数。
      最初对象的计数器是 1 。
      如果需要引用对象了,可以给对象发送  release 消息,这样对象计数器就加 1。
      当不需要引用对象了,可以给对象发送  release 消息,这样对象计数器就减 1。
      当计数器减到 0,自动调用对象的 dealloc 函数,对象就会释放内存。
      计数器为 0 的对象不能再使用 release 和其他方法 。

retain / release 例子
      NSMutableString *str = [[NSMutableString alloc] init];
                                      // str 计数器为 1
      [str retain];                // str 计数器为 2
      [str retain];                // str 计数器为 3
      [str release];              // str 计数器为 2
      [str release];              // str 计数器为 1
      [str release];              // str 计数器为 0,   对象释放内存
   
内存管理总结
Objective - C 的内存管理机制与 .Net / Jave 那种全自动的垃圾回收机制是不同的,它本质上还是 C 语言中的手动管理方式,只不过稍微加了一些自动方式。
      Objective - C 的内存管理是基于引用计数的。要做的事情只是关注的引用,而释放内存的工作实际上由运行环境完成。
      在最简单的情形中,分配的(alloc)对象,或者是保留(retain)在一些地方的对象,都需要发送一个 release 消息。这也意味着,如果使用了一次 alloc,然后又 retain 了一次,那你需要 release 两次才能释放对象的内存。

下面三种增加对象技术器
      1. 当明确的使用 alloc 方法来分配对象。
      2. 当明确的使用 copy [WithZone:] 或者 murableCopy[WithZone:] 来 copy 对象时。
      3. 当明确使用 retain 消息。

      上述三种方法使得计数器增加,那么就需要使用 [auto] release 来明确释放对象,也就是递减计数器。

遛狗原则举例 (一只狗时)这方法不够完善

// Dog.h#import <Foundation/Foundation.h>@interface Dog : NSObject{ int _ID;}@property int ID;@end

// Dog.m#import "Dog.h"@implementation Dog@synthesize ID = _ID;- (void) dealloc{ NSLog(@"dog %d is dealloc", _ID); [super dealloc];}@end


// Person.h#import <Foundation/Foundation.h>#import "Dog.h"@interface Person : NSObject{ Dog *_dog;}- (void) setDog:(Dog *)aDog;- (Dog *) dog;@end

// Persen.m

@implementation Person- (void) setDog:(Dog *)aDog{ if (aDog != _dog) {// _dog = aDog;// [_dog retain]; _dog = [aDog retain]; // 让计数器 +1 }}- (Dog *) dog{ return _dog;}- (void) dealloc{ NSLog(@"person is delloc"); // 把人拥有的 _dog 释放 [_dog release]; [super dealloc];}@end


// main.m#import <Foundation/Foundation.h>#import "Dog.h"#import "Person.h"int main (int argc, const char * argv[]){ @autoreleasepool { NSLog(@"Hello, World!"); Dog *dog1 = [[Dog alloc] init]; [dog1 setID:1]; Person *xiaoLi = [[Person alloc] init]; // 小丽要遛狗 [xiaoLi setDog:dog1]; Person *xiaoWang = [[Person alloc] init]; [xiaoWang setDog:dog1]; NSLog(@"dog1 retain count1 is %ld", [dog1 retainCount]); // 输出:dog1 retain count1 is 3 [dog1 release]; NSLog(@"dog1 retain count2 is %ld", [dog1 retainCount]); // 输出:dog1 retain count2 is 2 [xiaoWang release]; NSLog(@"dog1 retain count3 is %ld", [dog1 retainCount]); // 输出:person is delloc // :dog1 retain3 count is 1 [xiaoLi release]; // 输出:person is delloc // :dog 1 is dealloc } return 0;}


遛狗原则举例2 (两只狗时)这方法比较完善

// Dog.h#import <Foundation/Foundation.h>@interface Dog : NSObject{ int _ID;}@property int ID;@end

// Dog.m#import "Dog.h"@implementation Dog@synthesize ID = _ID;- (void) dealloc{ NSLog(@"dog %d is dealloc", _ID); [super dealloc];}@end


// Person.h#import <Foundation/Foundation.h>#import "Dog.h"@interface Person : NSObject{ Dog *_dog;}- (void) setDog:(Dog *)aDog;- (Dog *) dog;@end

// Persen.m

@implementation Person- (void) setDog:(Dog *)aDog{ if (aDog != _dog) {

[_dog release]; // 要注意的地方,提前 release _dog = [aDog retain]; // 让计数器 +1 }}- (Dog *) dog{ return _dog;}- (void) dealloc{ NSLog(@"person is delloc"); // 把人拥有的 _dog 释放 [_dog release]; [super dealloc];}@end


// main.m#import <Foundation/Foundation.h>#import "Dog.h"#import "Person.h"int main (int argc, const char * argv[]){ @autoreleasepool { Dog *dog1 = [[Dog alloc] init]; [dog1 setID:1]; Dog *dog2 = [[Dog alloc] init]; [dog2 setID:2]; Person *xiaoLi = [[Person alloc] init]; // 小丽要遛狗 [xiaoLi setDog:dog1]; [xiaoLi setDog:dog2]; NSLog(@"dog1 retain count is %ld", [dog1 retainCount]); //输出:dog1 retain count is 1 [dog1 release]; //输出:dog 1 is dealloc NSLog(@"dog2 retain count is %ld", [dog2 retainCount]); //输出:dog2 retain count is 2 [xiaoLi release]; //输出:person is delloc NSLog(@"dog2 retain count is %ld", [dog2 retainCount]); //输出:dog2 retain count is 1 [dog2 release]; //输出:dog 2 is dealloc } return 0;}

 

原创粉丝点击