Objective-C学习手册

Objective-C之我所理解的内存管理

2016-09-19  本文已影响56人  Bestmer

前言

伴随着iOS5的发布,在Xcode4.2中加入了一个振奋人心的新特性。ARC,开启这个特性后,帮我们省去了许多内存管理的代码,让我们把更多的精力集中到功能的实现上。虽然ARC如此的完美,但作为iOS Developer,学习MRC,同样的重要。


为什么要学内存管理 ?


内存管理的两种方式


哪些变量需要做内存管理


MRC


引用计数器


Person *p = [[Person alloc] init]; // 使用alloc创建一个新对象,对象引用计数器 = 1
[p retain]; // 给对象发送一条retain消息,对象引用计数器 + 1 = 2
[p release]; // 给对象发送一条release消息,对象引用计数器 - 1 = 1
[p release]; // 给对象发送一条release消息,对象引用计数器 - 1 = 0,指针所指向的对象的内存被释放

dealloc方法


- (void)dealloc
{
    NSLog(@"Person dealloc");

    // release对象所拥有资源
    [_room release];
    // 设置为nil可以避免野指针错误(其实可以不设置,只是写了显得有逼格)
    _room = nil;

    [super dealloc];
}

僵尸对象、野指针与空指针

注: 默认情况下,Xcode是不会监听僵尸对象的,所以需要我们自己手动开启,开启监听僵尸对象步骤为: Edit Scheme ->; Run ->; Diagnostics ->; Objective-C的Enable Zombie Objects打钩,这样便可以在因为僵尸对象报错的时候给出更多错误信息

 // 引用计数器 = 1
Person *p = [[Person alloc] init];

 // 引用计数器 - 1 = 0,指针所指向的对象的内存被释放
[p release];

// 这句给野指针发送消息,会报野指针错误,开启监听僵尸对象会给出错误信息
// -[Person release]: message sent to deallocated instance 0x100206fd0
[p release]; 

自动释放池

自动释放池提供了延迟放弃一个对象的所有权的机制,比如想要在一个方法中返回一个对象,如果先使用release放弃了该对象的所有权,那么return返回的对象便是一个僵尸对象,如果先进行return返回,那么便无法放弃该对象的所有权,导致了内存泄漏


NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
// do something...
[pool release];
@autoreleasepool
{
    // do something...
}

注1: 自动释放池被销毁时,只是给池中所有对象发送一条release消息,不代表对象一定会被释放

注2: 对象在自动释放池中每收到一条autorelease消息,在自动释放池被销毁时,对象都会收到一次release消息



ARC


注: OC中的ARC和Java中的垃圾回收机制不一样,Java中的垃圾回收是系统做的,而OC中的ARC是编译器做的


// MRC
@interface Person : NSObject

@property (retain) NSNumber *number;

@end

@implementation Person

- (void)dealloc
{
    NSLog(@"Person dealloc");

    [_number release];

    [super dealloc];
}

@end

Person *person = [[Person alloc] init];
NSNumber *number = [[NSNumber alloc] initWithInt:2];
person.number = number;

[number release];
[person release];
// perosn和number正常被释放
// ARC
@interface Person : NSObject

@property (strong) NSNumber *number;

@end

@implementation Person

- (void)dealloc
{
    NSLog(@"Person dealloc");
}

@end

Person *person = [[Person alloc] init];
NSNumber *number = [[NSNumber alloc] initWithInt:2];
person.number = number;

// perosn和number出了作用域正常被释放
// 错误
@property NSString *newTitle;

// 正确
@property (getter=theNewTitle) NSString *newTitle;

ARC引入的新特性

两个属性修饰符: strong和weak

// 下面这句对于strong的示例,与此同义: @property(retain) MyClass *myObject;
@property(strong) MyClass *myObject;

// 下面这句对于weak的示例,与此相似: @property(assign) MyClass *myObject;
// 使用assign修饰的指针所指向的对象如果被释放,该指针会变成野指针;使用weak修饰的指针所指向的对象如果被释放,该指针会变成空指针
@property(weak) MyClass *myObject;

注: 其实就是将MRC中的assign分成了两个部分,分别用于修饰OC对象与基本数据类型


四个变量修饰符

在ARC中新增了四个变量修饰符: 双下划线strong、双下划线weak、双下划线unsafe_unretained和双下划线autoreleasing,其中双下划线strong是默认修饰符,下面介绍一下这四个变量修饰符


// 规则
ClassName * qualifier variableName;

// 正确示例
MyClass * __weak myWeakReference;
MyClass * __unsafe_unretained myUnsafeReference;

// 错误示例(虽然错误,但是编译器会默认为正确,官方说法为"forgiven")
__weak MyClass * myWeakReference;
__unsafe_unretained MyClass * myUnsafeReference;

注: 在直接使用__weak修饰变量指向一个刚创建的对象时,需要注意对象刚刚创建出来就会释放的情况

NSString * __weak string = [[NSString alloc] initWithFormat:@"loly"];
// 因为没有强指针指向该对象,该对象会立即被释放

最后

温故而知新。

上一篇 下一篇

猜你喜欢

热点阅读