深入浅出Object-C内存管理
     演讲人:冲浪
内存管理规则
        只能释放或自动释放         所拥有的对象

[MyObject alloc]
[MyObject retain];
[MyObject copy];
[MyObject autorelease];
保留计数
Objective-C使用了一   叫做持有计数(Retain Count)的机制来管理内
存中的对象。


    创建一个对象,该对象的保留计数为1。

    向一个对象发送retain消息时,该对象的保留计数加1。

    向一个对象发送release消息时,该对象的保留计数        1。

    向一个对象发送autorelease消息时,该对象的保留计数会在
    将来的某个阶段       1。
例1:
- (void)printHello {

    NSString *string = [[NSString alloc] initWithString:@"Hello"];

    NSLog(string);

    [string release];

}

/ 用 alloc 创建对象 使 [string releaseCount] = 1
 /
例2:
- (void)printHello {

    NSString *string; = [NSString stringWithFormat:@"Hello"];

    NSLog(string);

}

/ 你拼不拥有 string ,所以你无需 release
 /



                        Q:它们差          在     里?
什么情况下用 autorelease 自动释放?
    重点:autorelease并不是“自动释放”,而是“延后释放”,在一个运行周期
    后被标记为autorelease会被释放掉。

例1:
– (NSArray *)sprockets {

   NSArray *array = [[NSArray alloc] initWithObjects:mainSprocket,
auxiliarySprocket, nil];

    return [array autorelease];

}

/ 正
 /     使用 autorelease
例2:
– (NSArray *)sprockets {

    NSArray *array = [[NSArray alloc]
initWithObjects:mainSprocket,auxiliarySprocket, nil];

   return array;

}
/ 内存泄露
 /
例3:
– (NSArray *)sprockets {

    NSArray *array = [[NSArray alloc]
initWithObjects:mainSprocket,auxiliarySprocket, nil];

   [array release];

   return array;

}
/ 程序
 /       常退出,因为 array 过早释放
例4:
– (NSArray *)sprockets {

   NSArray *array = [NSArray
arrayWithObjects:mainSprocket,auxiliarySprocket, nil];

    return array;

}

/ 你并不拥有 arrayWithObjects ,所以你不需要释放
 /
自动释放池
1.置于一个堆栈中,通常被称为被“嵌套”的。

2.新的自动释放池,它被添加到堆栈的顶部。

3. 对象收到autorelease,它被添加到当前线程栈顶的自动释放池中。

4.当被回收时,从堆栈中被删除。

5.Application Kit会在一个事件周期的   端—比如鼠标按下事件—自动创建
一个自动释放池,并且在事件周期的结尾释放它.
共享对象的有效性
例1:
heisenObject = [array objectAtIndex:n];

[array removeObjectAtIndex:n];

/ heisenObject 无效
 /
例2:
id parent = <#create a parent
object#>;

/ ...
 /

heisenObject = [parent child] ;

[parent release];

/ heisenObject 无效
 /
例3:
heisenObject = [[array objectAtIndex:n]
retain];

[array removeObjectAtIndex:n];

/ use heisenObject.
 /

[heisenObject release];

/ 正常运行
 /
集合
例1
NSMutableArray *array;

NSUInteger i;

for (i = 0; i < 10; i++) {

     NSNumber *convenienceNumber = [NSNumber numberWithInteger:i];

     [array addObject:convenienceNumber];

}

//在这段代码中,             没有调用alloc,因此也没有必要调用release。没有必要
保留新的数字对象(convenienceNumber),因为数组会为                    代劳。
例2
NSMutableArray *array;

NSUInteger i;

for (i = 0; i < 10; i++) {

    NSNumber *allocedNumber = [[NSNumber alloc] initWithInteger: i];

    [array addObject:allocedNumber];

    [allocedNumber release];

}

/ 由于数组在用addObject:方法添加数字时对其进行了保留 + 1,因此只要
 /
它还在数组中就不会被释放。
从方法返回的对象
例1
- (NSString *)fullName {

    NSString *string = [NSString stringWithFormat:@"%@ %@", firstName,
lastName];

     return string;

}
//    并不拥有stringWithFormat返回的字符串,所以它可以安全地从该方法
中返回
例2
- (NSString *)fullName {

  NSString *string = [[[NSString alloc] initWithFormat:@"%@
%@", firstName, lastName] autorelease];

     return string;

}
//    拥有alloc返回的字符串,但           随后向它发送了一条autorelease消
息,因此在          失去它的引用之前,         已经放弃了所有权
例3:
- (NSString *)fullName {

   NSString *string = [[[NSString alloc] initWithFormat:@"%@ %@",
firstName, lastName] release];

    return string;

}

/ 错误
 /
例4:
- (NSString *)fullName {

   NSString *string = [[NSString alloc] initWithFormat:@"%@ %@",
firstName, lastName];

   return string;

}
/ 内存泄露
 /
存取方法
MyClass.h:
@interface MyClass : NSObject {
   MyObject *myObject;
}
@property (nonatomic, retain) MyObject *myObject;
@end
MyClass.m:
@synthesize myObject;

-(id)init{
    if(self = [super init]){
        MyObject * aMyObject = [[MyObject alloc] init];
        self.myObject = aMyObject;
        [aMyObject release];
    }
    return self;
}




 Q: 为什么要这么 杂的赋值? 为什么要加self. ? 直接写成self.myObject
 = [[MyObject alloc] init];不是也没有错么? 不加self有时好像也是正常的?
看以下例子retainCount变化:

间接赋值:

     1.加self.:
       MyObject * aMyObject = [[MyObject alloc] init]; //aMyObject
retainCount = 1;
       self.myObject = aMyObject; //myObject retainCount = 2;
       [aMyObject release];//myObject retainCount = 1;

      2. 不加self.:
       MyObject * aMyObject = [[MyObject alloc] init]; //aMyObject
retainCount = 1;
       myObject = aMyObject; //myObject retainCount = 1;
       [aMyObject release];//对象己经被释放
直接赋值:

   3.加self.:
   self.myObject = [[MyObject alloc] init]; //myObject retainCount = 2;

   4. 不加self.:
   myObject = [[MyObject alloc] init]; //myObject retainCount = 1;
MyClass.h
@interface MyClass : NSObject {
   MyObject * _myObject;
}
@property (nonatomic, retain) MyObject *myObject;
@end


MyClass.m
@synthesize myObject = _myObject;



 如果你用 self._myObject = aMyObject; 或者 myObject = aMyObject;
 你会得到一个错误. 为什么             ?

 self.myObject = [[MyObject alloc] init]; 为什么会有内存泄露?
实现方法

get方法是:
-(MyObject*)myObject{
   return _myObject;
}



                          Set方法是:
                          / assign
                           /
                          -(void)setMyObject:(id)newValue{
                              _myObject = newValue;
                          }
/ retain
 /
-(void)setMyObject:(id)newValue{
    if (_myObject != newValue) {
        [_myObject release];
        _myObject = [newValue retain];
    }
}

                                   / copy
                                    /
                                   -(void)setMyObject:(id)newValue{
                                       if (_myObject != newValue) {
                                           [_myObject release];
                                           _myObject = [newValue copy];
                                       }
                                   }
例子

NSString* s = [[NSString alloc]initWithString:@”This is a test string”];
s = [s substringFromIndex:[s rangeOfString:@"a"].location];//内存泄露
[s release];//错误释放
谢谢

冲浪 Object-c

  • 1.
  • 2.
    内存管理规则 只能释放或自动释放 所拥有的对象 [MyObject alloc] [MyObject retain]; [MyObject copy]; [MyObject autorelease];
  • 3.
    保留计数 Objective-C使用了一 叫做持有计数(Retain Count)的机制来管理内 存中的对象。 创建一个对象,该对象的保留计数为1。 向一个对象发送retain消息时,该对象的保留计数加1。 向一个对象发送release消息时,该对象的保留计数 1。 向一个对象发送autorelease消息时,该对象的保留计数会在 将来的某个阶段 1。
  • 4.
    例1: - (void)printHello { NSString *string = [[NSString alloc] initWithString:@"Hello"]; NSLog(string); [string release]; } / 用 alloc 创建对象 使 [string releaseCount] = 1 /
  • 5.
    例2: - (void)printHello { NSString *string; = [NSString stringWithFormat:@"Hello"]; NSLog(string); } / 你拼不拥有 string ,所以你无需 release / Q:它们差 在 里?
  • 6.
    什么情况下用 autorelease 自动释放? 重点:autorelease并不是“自动释放”,而是“延后释放”,在一个运行周期 后被标记为autorelease会被释放掉。 例1: – (NSArray *)sprockets { NSArray *array = [[NSArray alloc] initWithObjects:mainSprocket, auxiliarySprocket, nil]; return [array autorelease]; } / 正 / 使用 autorelease
  • 7.
    例2: – (NSArray *)sprockets{ NSArray *array = [[NSArray alloc] initWithObjects:mainSprocket,auxiliarySprocket, nil]; return array; } / 内存泄露 /
  • 8.
    例3: – (NSArray *)sprockets{ NSArray *array = [[NSArray alloc] initWithObjects:mainSprocket,auxiliarySprocket, nil]; [array release]; return array; } / 程序 / 常退出,因为 array 过早释放
  • 9.
    例4: – (NSArray *)sprockets{ NSArray *array = [NSArray arrayWithObjects:mainSprocket,auxiliarySprocket, nil]; return array; } / 你并不拥有 arrayWithObjects ,所以你不需要释放 /
  • 10.
  • 11.
    共享对象的有效性 例1: heisenObject = [arrayobjectAtIndex:n]; [array removeObjectAtIndex:n]; / heisenObject 无效 /
  • 12.
    例2: id parent =<#create a parent object#>; / ... / heisenObject = [parent child] ; [parent release]; / heisenObject 无效 /
  • 13.
    例3: heisenObject = [[arrayobjectAtIndex:n] retain]; [array removeObjectAtIndex:n]; / use heisenObject. / [heisenObject release]; / 正常运行 /
  • 14.
    集合 例1 NSMutableArray *array; NSUInteger i; for(i = 0; i < 10; i++) { NSNumber *convenienceNumber = [NSNumber numberWithInteger:i]; [array addObject:convenienceNumber]; } //在这段代码中, 没有调用alloc,因此也没有必要调用release。没有必要 保留新的数字对象(convenienceNumber),因为数组会为 代劳。
  • 15.
    例2 NSMutableArray *array; NSUInteger i; for(i = 0; i < 10; i++) { NSNumber *allocedNumber = [[NSNumber alloc] initWithInteger: i]; [array addObject:allocedNumber]; [allocedNumber release]; } / 由于数组在用addObject:方法添加数字时对其进行了保留 + 1,因此只要 / 它还在数组中就不会被释放。
  • 16.
    从方法返回的对象 例1 - (NSString *)fullName{ NSString *string = [NSString stringWithFormat:@"%@ %@", firstName, lastName]; return string; } // 并不拥有stringWithFormat返回的字符串,所以它可以安全地从该方法 中返回
  • 17.
    例2 - (NSString *)fullName{ NSString *string = [[[NSString alloc] initWithFormat:@"%@ %@", firstName, lastName] autorelease]; return string; } // 拥有alloc返回的字符串,但 随后向它发送了一条autorelease消 息,因此在 失去它的引用之前, 已经放弃了所有权
  • 18.
    例3: - (NSString *)fullName{ NSString *string = [[[NSString alloc] initWithFormat:@"%@ %@", firstName, lastName] release]; return string; } / 错误 /
  • 19.
    例4: - (NSString *)fullName{ NSString *string = [[NSString alloc] initWithFormat:@"%@ %@", firstName, lastName]; return string; } / 内存泄露 /
  • 20.
    存取方法 MyClass.h: @interface MyClass :NSObject { MyObject *myObject; } @property (nonatomic, retain) MyObject *myObject; @end
  • 21.
    MyClass.m: @synthesize myObject; -(id)init{ if(self = [super init]){ MyObject * aMyObject = [[MyObject alloc] init]; self.myObject = aMyObject; [aMyObject release]; } return self; } Q: 为什么要这么 杂的赋值? 为什么要加self. ? 直接写成self.myObject = [[MyObject alloc] init];不是也没有错么? 不加self有时好像也是正常的?
  • 22.
    看以下例子retainCount变化: 间接赋值: 1.加self.: MyObject * aMyObject = [[MyObject alloc] init]; //aMyObject retainCount = 1; self.myObject = aMyObject; //myObject retainCount = 2; [aMyObject release];//myObject retainCount = 1; 2. 不加self.: MyObject * aMyObject = [[MyObject alloc] init]; //aMyObject retainCount = 1; myObject = aMyObject; //myObject retainCount = 1; [aMyObject release];//对象己经被释放
  • 23.
    直接赋值: 3.加self.: self.myObject = [[MyObject alloc] init]; //myObject retainCount = 2; 4. 不加self.: myObject = [[MyObject alloc] init]; //myObject retainCount = 1;
  • 24.
    MyClass.h @interface MyClass :NSObject { MyObject * _myObject; } @property (nonatomic, retain) MyObject *myObject; @end MyClass.m @synthesize myObject = _myObject; 如果你用 self._myObject = aMyObject; 或者 myObject = aMyObject; 你会得到一个错误. 为什么 ? self.myObject = [[MyObject alloc] init]; 为什么会有内存泄露?
  • 25.
    实现方法 get方法是: -(MyObject*)myObject{ return _myObject; } Set方法是: / assign / -(void)setMyObject:(id)newValue{ _myObject = newValue; }
  • 26.
    / retain / -(void)setMyObject:(id)newValue{ if (_myObject != newValue) { [_myObject release]; _myObject = [newValue retain]; } } / copy / -(void)setMyObject:(id)newValue{ if (_myObject != newValue) { [_myObject release]; _myObject = [newValue copy]; } }
  • 27.
    例子 NSString* s =[[NSString alloc]initWithString:@”This is a test string”]; s = [s substringFromIndex:[s rangeOfString:@"a"].location];//内存泄露 [s release];//错误释放
  • 28.