内存管理

- dealloc

当对象的引用计数变为 0 时,系统会给该对象发送 dealloc 消息释放内存。

MRC

// Teacher.h
#import <Foundation/Foundation.h>

@interface Teacher : NSObject

@property (nonatomic , copy) NSString *name;

@end 


// Teacher.m
#import "Teacher.h"

@implementation Teacher

- (void) dealloc {
	NSLog(@"Teacher dealloc called");
	[super dealloc];
}

@end

// Student.h
#import <Foundation/Foundation.h>
#import "Teacher.h"

@interface Student : NSObject

@property (nonatomic , retain) Teacher *teacher;

@end


// Student.m
#import "Student.h"

@implementation Student

- (void) dealloc {
	NSLog(@"Student dealloc called");
	[self.teacher release]; // teacher count == 0 | teacher dealloc
	[super dealloc];
}

// 调用
Teacher *teacher = [[Teacher alloc]init]; // teacher count == 1
teacher.name = @"MissLiu";

Student *student = [[Student alloc]init]; // student count == 1
student.teacher = teacher; // teacher count == 2
[teacher release]; // teacher count == 1

[student retain]; // student count == 2
[student release]; // student count == 1
[student release]; // student dealloc

@end

// 打印
2017-03-31 14:10:14.069 MRC[30203:6093362] Student dealloc called
2017-03-31 14:10:14.070 MRC[30203:6093362] Teacher dealloc called

小结:

  • dealloc 实际释放的是堆内存(系统无法自动回收)
  • 对使用了 retain、copy、mutableCopy、alloc 或者 new 方法的任何对象,以及具有 retain 和 copy 特性的属性进行释放,需要覆盖 dealloc 方法,使得在对象被释放的时候能够释放这些实例变量。

ARC

- (void) dealloc {
	NSLog(@"dealloc called"); // 监听对象是否释放
}

autorelease
  • 将对象放入自动释放池栈栈顶的自动释放池中。
  • 自动释放池销毁或者调用 drain 消息时 对象会调用 release 消息

自动释放池

// 正确的三种写法

// 使用 @autoreleasepool 创建一个自动释放池放于栈顶 
@autoreleasepool {
    Student *s1 = [Student new];
    [s1 retain];
    [s1 release]; // count == 1
    [s1 autorelease]; // 将 s1 放入栈顶的自动释放池,当自动释放池销毁或者调用 drain 消息时 s1 会调用 release 消息        
    s1.name = @"iMock"; // 此时 s1 指针指向的堆内存还没有释放。
}
// 自动释放池销毁,池中的每个对象都会收到 release 消息。此时 s1 指针指向的堆内存释放

// 等效于第一种写法
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc]init];

Student *s2 = [Student new];
[s2 retain];
[s2 release];
[s2 autorelease];
s2.name = @"iMock";

[pool release];

// 不创建新的自动释放池,将 s3 放入当前栈顶的自动释放池
Student *s3 = [Student new];
[s3 retain];
[s3 release];
[s3 autorelease];
s3.name = @"iMock";    

小结:

  • 推迟调用 release 的时间。
  • 自动释放池中存放的都是对象的引用。
  • 由一个自动释放池栈维护。
  • 自动释放池对象调用 drain 消息,会给池中的每个对象发一次 release 消息。
  • 自动释放池对象调用 release 消息,会给池中的每个对象发一次 release 消息,同时会销毁自己。
posted @ 2017-03-31 14:57  上水的花  阅读(133)  评论(0)    收藏  举报