2

Objective-C 内存管理

 3 years ago
source link: http://blog.danthought.com/programming/2020/11/30/objective-c-memory-management/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

本文并不是一篇完整的教程,更像一篇快速笔记,讲解 Objective-C 中的内存管理。

Objective C

手动引用计数

当创建对象时,初始的引用计数为 1

[Object new]

当如下持有对象时,引用计数加 1

someObject = [object retain]

当如下不再需要对象时,引用计数减 1

[object release]

当使用 alloc 创建一个对象,然后将它作为方法调用的结果返回,尽管此方法不再使用这个对象,但是并不能释放它,因为需要将这个对象作为方法的返回值,创建 NSAutoreleasePool 类的目的就是希望能够解决这个问题,自动释放池可以帮助追踪需要延迟一些时间释放的对象:

NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];

// Code benefitting from a local autorelease pool.
id result = [self doSomething];

[pool release];
- (id)doSomething {
  return [result autorelease];
}

声明属性时使用 assign

@property (nonatomic, assign) int i;

self.property = newValue;

// assign 直接指向对象引用
property = newValue

声明属性时使用 retain

@property (nonatomic, retain) NSMutableArray *data;

// retain 直接指向对象引用,引用计数加 1
if (property != newValue) {
  [property release];
  property = [newValue retain];
}

声明属性时使用 copy

@property (nonatomic, copy) NSString *text;

// copy 拷贝成新的对象,指向这个对象引用
if (property != newValue) {
  [property release];
  property = [newValue copy];
}

自动引用计数

ARC 仍然采用了引用计数,不过编译器会检测出何时需要保持对象,何时需要自动释放对象,补上这些代码,不能也不需要使用 retainrelease,以及 autorelease

__strong 修饰符,强引用:

id __strong obj = [[NSObject alloc] init];

__weak 修饰符,弱引用,弱引用不能持有对象实例,所以下面的代码,编译器会发出警告:

id __weak obj = [[NSObject alloc] init];

可以改写成,当指向的对象被释放,obj1 被置为 nil

id __strong obj0 = [[NSObject alloc] init];
id __weak obj1 = obj0;

__unsafe_unretained 修饰符,不安全的所有权修饰符,同弱引用一样不能持有对象实例,所以下面的代码,编译器会发出警告:

id __unsafe_unretained obj = [[NSObject alloc] init];

可以改写成,当指向的对象被释放,obj1 不会被置为 nil,所以使用 obj1 时,对象有可能已经被释放,引起 Crash:

id __strong obj0 = [[NSObject alloc] init];
id __unsafe_unretained obj1 = obj0;

__autoreleasing@autoreleasepool 结合使用,@autoreleasepool 这个指令围住的语句块决定了自动释放池的上下文,任何在这个上下文中创建的对象都是自动释放的,在自动释放池块结束的时候销毁这些对象:

int main(int argc, char * argv[]) {
  @autoreleasepool {
    id __autoreleasing obj = [[NSObject alloc] init];
  }
}

声明属性时新增 strong 会 retain 新值,release 旧值,让编译器保证在事件循环中通过对赋值执行保持操作,强属性能够存活下来:

@property (nonatomic, strong) NSMutableArray *data;

声明属性时新增 weak 像 assign 只是赋值,但是当引用的对象释放时,弱变量会被自动设置为 nil:

@property (nonatomic, weak) NSMutableArray *data;

声明属性时使用 unsafe_unretained,注意属性默认特性是 unsafe_unretained

@property (nonatomic) NSMutableArray *data;

self.property = newValue;

// 像 assign 只是赋值,但是指向的对象被销毁时,不会赋值为 nil
property = newValue

iOS 应用运行在事件循环中,为了处理新的事件,系统会创建一个新的自动释放池上下文,调用到应用中的一些方法用于处理事件,再从方法返回,系统会继续等待下一个事件的发生,然而,做这些事件之前,自动释放池上下文已经结束,意味着自动释放池的对象可能会被销毁。参考 博文 - iOS 基础 - RunLoop 和 定时器


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK