内容简介:自动引用计数(ARC)是一种编译器功能,它提供 Objective-C 对象的自动内存管理。ARC 不是必须考虑 retain 和 release 操作,而是让你专注于有趣的代码,对象图以及应用程序中对象之间的关系。ARC 的工作原理是在编译时添加代码,以确保对象在必要时存活,但不会一直存活。从概念上讲,它通过为你添加适当的内存管理调用,遵循与手动引用计数相同的内存管理约定。为了让编译器生成正确的代码,ARC 限制了你可以使用的方法以及如何使用免费桥接(toll-free bridging)。ARC 还为对
自动引用计数(ARC)是一种编译器功能,它提供 Objective-C 对象的自动内存管理。ARC 不是必须考虑 retain 和 release 操作,而是让你专注于有趣的代码,对象图以及应用程序中对象之间的关系。
摘要
ARC 的工作原理是在编译时添加代码,以确保对象在必要时存活,但不会一直存活。从概念上讲,它通过为你添加适当的内存管理调用,遵循与手动引用计数相同的内存管理约定。
为了让编译器生成正确的代码,ARC 限制了你可以使用的方法以及如何使用免费桥接(toll-free bridging)。ARC 还为对象引用和声明的属性引入了新的生命周期限定符。
ARC 在 Xcode 4.2 编译的 OS X v10.6 和 v10.7 (64位应用程序) 以及 iOS 4 和 iOS 5 应用程序中提供支持。OS X v10.6 和 iOS 4 不支持弱引用。
Xcode 提供了一个工具,可以自动执行 ARC 转换的机械部分(例如删除 retain 和 release 调用),并帮助你修复迁移器无法自动处理的问题(选择 Edit > Refactor > Convert to Objective-C ARC)。迁移 工具 将项目中的所有文件转换为使用 ARC。如果对某些文件使用手动引用计数更方便,也可以选择在每个文件的基础上使用 ARC。
ARC 概述
ARC 不会记住何时使用 retain,release 和 autorelease,而是评估对象的生命周期要求,并在编译时自动为你插入适当的内存管理调用。编译器还会为你生成适当的 dealloc 方法。通常,如果你只使用 ARC,则只有在需要与使用手动引用计数的代码进行互操作时,传统的 Cocoa 命名约定才是重要的。
Person 类的完整且正确的实现可能如下所示:
@interface Person : NSObject @property NSString *firstName; @property NSString *lastName; @property NSNumber *yearOfBirth; @property Person *spouse; @end @implementation Person @end 复制代码
(默认情况下,对象属性是 strong。)
使用 ARC,你可以实现这样一种人为的方法:
- (void)contrived { Person *aPerson = [[Person alloc] init]; [aPerson setFirstName:@"William"]; [aPerson setLastName:@"Dudney"]; [aPerson setYearOfBirth:[[NSNumber alloc] initWithInteger:2011]]; NSLog(@"aPerson: %@", aPerson); } 复制代码
ARC 负责内存管理,以便 Person 和 NSNumber 对象都不会泄露。
你还可以安全地实现 Person 的 takeLastNameFrom: 方法,如下所示:
- (void)takeLastNameFrom:(Person *)person { NSString *oldLastname = [self lastName]; [self setLastName:[person lastName]]; NSLog(@"Lastname changed from %@ to %@", oldLastname, [self lastName]); } 复制代码
ARC 确保在 NSLog 语句之前不释放 oldLastName。
ARC 实施新规则
为了工作,ARC 强制使用其他编译器模式时不存在的一些新规则。规则旨在提供完全可靠的内存管理模型; 在某些情况下,他们只是执行最佳实践,在其他一些情况下,他们简化了代码,或者是你不必处理内存管理的明显推论。如果违反这些规则,则会立即得到编译时错误,而不是在运行时可能会出现的细微错误。
-
你无法显式调用 dealloc,也无法实现或调用 retain,release,retainCount 或 autorelease。
禁止扩展到使用 @selector(retain),@selector(release) 等。
如果需要管理除释放实例变量之外的资源,则可以实现 dealloc 方法。你不必(实际上你不能)释放实例变量,但你可能需要在系统类和未使用 ARC 编译的其他代码上调用 [systemClassInstance setDelegate:nil]。
ARC 中的自定义 dealloc 方法不需要调用 [super dealloc](它实际上会导致编译器错误)。链接到 super 是由编译器自动执行的。
你仍然可以将 CFRetain,CFRelease 和其他相关功能与 Core Foundation 样式的对象一起使用。
-
你不能使用 NSAllocateObject 或 NSDeallocateObject。
你可以使用 alloc 创建对象; 运行时负责 deallocating 对象。
-
你不能在 C 结构中使用对象指针。
你可以创建一个 Objective-C 类来管理数据,而不是使用结构。
-
id 和 void * 之间不是简单的映射。
你必须使用特殊的强制转换来告诉编译器有关对象的生命周期。你需要在 Objective-C 对象和作为函数参数传递的 Core Foundation 类型之间进行转换。
-
你不能使用 NSAutoreleasePool 对象。
ARC 提供了 @autoreleasepool 块。它们具有比 NSAutoreleasePool 更有效的优点。
-
你不能使用内存区域(memory zones)。
不再需要使用 NSZone - 无论如何它们都会被现代的 Objective-C 运行时忽略。
为了允许与 manual retain-release 代码进行互操作,ARC 对方法命名施加了约束:
- 你不能为访问者提供以 new 开头的名称。这反过来意味着你不能,例如,声明一个名称以 new 开头的属性,除非你指定一个不同的 getter:
// Won't work: @property NSString *newTitle; // Works: @property (getter=theNewTitle) NSString *newTitle; 复制代码
ARC 推出新的生命周期限定符
ARC 为对象和弱引用引入了几个新的生命周期限定符。弱引用不会延长它指向的对象的生命周期,并且在没有对该对象的强引用时自动变为 nil。
你应该利用这些限定符来管理程序中的对象图。特别是,ARC不能防范强引用循环(以前称为 retain cycles)。明智地使用弱饮用将有助于确保你不会创建循环引用。
属性特性
关键字 weak 和 strong 将作为新声明的属性特性引入,如以下示例所示。
// The following declaration is a synonym for: @property(retain) MyClass *myObject; @property(strong) MyClass *myObject; // The following declaration is similar to "@property(assign) MyClass *myObject;" // except that if the MyClass instance is deallocated, // the property value is set to nil instead of remaining as a dangling pointer. @property(weak) MyClass *myObject; 复制代码
在 ARC 下,strong 是对象类型的默认值。
变量限定符
你可以像使用 const 一样为变量使用以下生命周期限定符。
__strong __weak __unsafe_unretained __autoreleasing 复制代码
- __strong 是默认值。只要存在指向它的强指针,对象就会保持“活着”。
- __weak 指定不使引用对象保持活动状态的引用。当没有对象的强引用时,弱引用设置为 nil。
- __unsafe_unretained 指定一个引用,该引用不会使引用的对象保持活动状态,并且在没有对该对象的强引用时不会设置为 nil。如果它引用的对象被释放,则指针悬空(dangling)。
- __autoreleasing 用于表示通过引用(id *)传递的参数,并在返回时自动释放。
你应该正确装饰变量。在对象变量声明中使用限定符时,正确的格式为:
ClassName * qualifier variableName; 复制代码
例如:
MyClass * __weak myWeakReference; MyClass * __unsafe_unretained myUnsafeReference; 复制代码
其他变体在技术上是不正确的,但编译器“原谅”了。
在栈上使用 __weak 变量时要小心。请考虑以下示例:
NSString * __weak string = [[NSString alloc] initWithFormat:@"First Name: %@", [self firstName]]; NSLog(@"string: %@", string); 复制代码
尽管在初始赋值之后使用了字符串,但在赋值时没有对字符串对象的其他强引用; 因此,它立即被释放。log 语句显示 string 的值为 null。(在这种情况下,编译器会提供警告。)
你还需要注意通过引用传递的对象。以下代码将起作用:
NSError *error; BOOL OK = [myObject performOperationWithError:&error]; if (!OK) { // Report the error. // ... 复制代码
但是,错误声明是隐式的:
NSError * __strong e; 复制代码
方法声明通常是:
-(BOOL)performOperationWithError:(NSError * __autoreleasing *)error; 复制代码
因此编译器重写代码:
NSError * __strong error; NSError * __autoreleasing tmp = error; BOOL OK = [myObject performOperationWithError:&tmp]; error = tmp; if (!OK) { // Report the error. // ... 复制代码
局部变量声明(__strong)和参数(__autoreleasing)之间的不匹配会导致编译器创建临时变量。当你获取 __strong 变量的地址时,可以通过声明参数 id __strong * 来获取原始指针。或者,你可以将变量声明为 __autoreleasing。
使用生命周期限定符来避免强引用循环
你可以使用生命周期限定符来避免强引用循环。例如,通常如果你有一个以父子层次结构排列的对象图表,并且父对象需要引用他们的孩子,反之亦然,那么你将使父对象指向子对象之间的引用为强引用,并且父对象与子对象之间的引用为弱引用。其他情况可能更微妙,特别是当它们涉及 block 对象时。
在手动引用计数模式下,__block id x; 具有不保留 x 的效果。在 ARC 模式下,__block id x; 默认为保留 x(就像所有其他值一样)。要在 ARC 下获得手动引用计数模式行为,可以使用 __unsafe_unretained __block id x;。然而,正如名称 __unsafe_unretained 所暗示的那样,具有非保留变量是危险的(因为它可以悬挂),因此不鼓励。两个更好的选择是使用 __weak(如果你不需要支持 iOS 4 或 OS X v10.6),或者将 __block 值设置为 nil 以打破引用循环。
以下代码片段使用有时在手动引用计数中使用的模式说明了此问题。
MyViewController *myController = [[MyViewController alloc] init…]; // ... myController.completionHandler = ^(NSInteger result) { [myController dismissViewControllerAnimated:YES completion:nil]; }; [self presentViewController:myController animated:YES completion:^{ [myController release]; }]; 复制代码
如上所述,你可以使用 __block 限定符并在完成处理程序中将 myController 变量设置为 nil:
MyViewController * __block myController = [[MyViewController alloc] init…]; // ... myController.completionHandler = ^(NSInteger result) { [myController dismissViewControllerAnimated:YES completion:nil]; myController = nil; }; 复制代码
或者,你可以使用临时 __weak 变量。以下示例说明了一个简单的实现:
MyViewController *myController = [[MyViewController alloc] init…]; // ... MyViewController * __weak weakMyViewController = myController; myController.completionHandler = ^(NSInteger result) { [weakMyViewController dismissViewControllerAnimated:YES completion:nil]; }; 复制代码
但是,对于 non-trivial cycles,你应该使用:
MyViewController *myController = [[MyViewController alloc] init…]; // ... MyViewController * __weak weakMyController = myController; myController.completionHandler = ^(NSInteger result) { MyViewController *strongMyController = weakMyController; if (strongMyController) { // ... [strongMyController dismissViewControllerAnimated:YES completion:nil]; // ... } else { // Probably nothing... } }; 复制代码
在某些情况下,如果类与 __weak 不兼容,则可以使用 __unsafe_unretained。然而,这对于 nontrivial cycles 来说变得不切实际,因为很难或不可能验证 __unsafe_unretained 指针仍然有效并且仍然指向相同的对象。
ARC 使用新语句来管理自动释放池
使用 ARC,你无法使用 NSAutoreleasePool 类直接管理自动释放池。相反,你使用 @autoreleasepool 块:
@autoreleasepool { // Code, such as a loop that creates a large number of temporary objects. } 复制代码
这种简单的结构允许编译器推断引用计数状态。在进入时,推送自动释放池。在正常退出(break,return,goto,fall-through 等)时,将弹出自动释放池。为了与现有代码兼容,如果 exit 是由异常引起的,则不会弹出自动释放池。
所有 Objective-C 模式都提供此语法。它比使用 NSAutoreleasePool 类更有效; 因此,我们鼓励你采用它代替使用 NSAutoreleasePool。
管理 Outlets 的模式在平台上变得一致
用于在 iOS 和 OS X 中声明 outlets 的模式随 ARC 而变化,并且在两个平台上变得一致。你应该采用的模式是:outlets 应该是弱的,除了从文件所有者到 nib 文件(或故事板场景)中应该很强的顶级对象的出口。
栈变量初始化为 nil
使用 ARC,现在使用 nil 隐式初始化 strong,weak 和 autoreleasing 栈变量。例如:
- (void)myMethod { NSString *name; NSLog(@"name: %@", name); } 复制代码
将为 name 的值记录 null,而不是崩溃。
使用编译器标志启用和禁用 ARC
使用新的 -fobjc-arc 编译器标志启用 ARC。如果对某些文件使用手动引用计数更方便,也可以选择在每个文件的基础上使用 ARC。对于使用 ARC 作为默认方法的项目,可以使用该文件的新 -fno-objc-arc 编译器标志为特定文件禁用 ARC。
Xcode 4.2 及更高版本的 OS X v10.6 及更高版本(64位应用程序)以及 iOS 4 及更高版本支持 ARC。OS X v10.6 和 iOS 4 不支持弱引用。Xcode 4.1 及更早版本中没有 ARC 支持。
管理 Toll-Free Bridging
在许多 Cocoa 应用程序中,你需要使用 Core Foundation 样式的对象,无论是来自 Core Foundation 框架本身(例如 CFArrayRef 还是 CFMutableDictionaryRef),还是来自采用 Core Foundation 约定的框架(如 Core Graphics)(你可以使用类似 CGColorSpaceRef 和 CGGradientRef 的类型))。
编译器不会自动管理 Core Foundation 对象的生命周期; 你必须根据 Core Foundation 内存管理规则调用 CFRetain 和 CFRelease(或相应的特定于类型的变体)。
如果在 Objective-C 和 Core Foundation 风格的对象之间进行转换,则需要使用强制转换(在 objc/runtime.h 中定义)或 Core Foundation 样式宏(在 NSObject.h 中定义)来告诉编译器对象的所有权语义:
-
__bridge 在 Objective-C 和 Core Foundation 之间传输指针,不转让所有权。
-
__bridge_retained 或 CFBridgingRetain 将一个 Objective-C 指针强制转换为 Core Foundation 指针,并将所有权转移给你。
你有责任调用 CFRelease 或相关函数来放弃对象的所有权。
-
__bridge_transfer 或 CFBridgingRelease 将非 Objective-C 指针移动到 Objective-C,并将所有权转移到 ARC。
ARC 负责放弃对象的所有权。
例如,如果你有这样的代码:
- (void)logFirstNameOfPerson:(ABRecordRef)person { NSString *name = (NSString *)ABRecordCopyValue(person, kABPersonFirstNameProperty); NSLog(@"Person's first name: %@", name); [name release]; } 复制代码
你可以用以下代替它:
- (void)logFirstNameOfPerson:(ABRecordRef)person { NSString *name = (NSString *)CFBridgingRelease(ABRecordCopyValue(person, kABPersonFirstNameProperty)); NSLog(@"Person's first name: %@", name); } 复制代码
编译器处理从 Cocoa 方法返回的 CF 对象
编译器理解返回 Core Foundation 类型的 Objective-C 方法遵循历史 Cocoa 命名约定。例如,编译器知道,在 iOS 中,UIColor 的 CGColor 方法返回的 CGColor 不归属。你仍必须使用适当的类型转换,如此示例所示:
NSMutableArray *colors = [NSMutableArray arrayWithObject:(id)[[UIColor darkGrayColor] CGColor]]; [colors addObject:(id)[[UIColor lightGrayColor] CGColor]]; 复制代码
使用所有权关键字转换函数参数
在函数调用中在 Objective-C 和 Core Foundation 对象之间进行转换时,需要告诉编译器有关传递对象的所有权语义。Core Foundation 对象的所有权规则是 Core Foundation 内存管理规则中指定的规则; Objective-C 对象的规则在 Advanced Memory Management Programming Guide 中指定。
在下面的代码片段中,传递给 CGGradientCreateWithColors 函数的数组需要适当的强制转换。arrayWithObjects: 返回的对象的所有权不会传递给函数,因此强制转换为 __bridge。
NSArray *colors = <#An array of colors#>; CGGradientRef gradient = CGGradientCreateWithColors(colorSpace, (__bridge CFArrayRef)colors, locations); 复制代码
代码片段在以下方法实现中的上下文中示出。另请注意 Core Foundation 内存管理功能的使用,这些功能由 Core Foundation 内存管理规则决定。
- (void)drawRect:(CGRect)rect { CGContextRef ctx = UIGraphicsGetCurrentContext(); CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceGray(); CGFloat locations[2] = {0.0, 1.0}; NSMutableArray *colors = [NSMutableArray arrayWithObject:(id)[[UIColor darkGrayColor] CGColor]]; [colors addObject:(id)[[UIColor lightGrayColor] CGColor]]; CGGradientRef gradient = CGGradientCreateWithColors(colorSpace, (__bridge CFArrayRef)colors, locations); CGColorSpaceRelease(colorSpace); // Release owned Core Foundation object. CGPoint startPoint = CGPointMake(0.0, 0.0); CGPoint endPoint = CGPointMake(CGRectGetMaxX(self.bounds), CGRectGetMaxY(self.bounds)); CGContextDrawLinearGradient(ctx, gradient, startPoint, endPoint, kCGGradientDrawsBeforeStartLocation | kCGGradientDrawsAfterEndLocation); CGGradientRelease(gradient); // Release owned Core Foundation object. } 复制代码
转换项目时的常见问题
迁移现有项目时,你可能会遇到各种问题。以下是一些常见问题以及解决方案。
-
你无法调用 retain,release 或 autorelease。
这是一个功能。你也写不出来:
while ([x retainCount]) { [x release]; } 复制代码
-
你不能调用 dealloc。
如果要在 init 方法中实现单例或替换对象,通常会调用 dealloc。对于单例,请使用共享实例模式。在 init 方法中,你不必再调用 dealloc,因为在覆盖 self 时将释放该对象。
-
你不能使用 NSAutoreleasePool 对象。
请改用新的 @autoreleasepool {} 结构。这会强制你的自动释放池上的块结构,并且比 NSAutoreleasePool 快约六倍。@autoreleasepool 甚至适用于非 ARC 代码。因为 @autoreleasepool 比 NSAutoreleasePool 快得多,所以许多旧的“性能黑客”可以简单地用无条件的 @autoreleasepool 替换。
迁移器处理 NSAutoreleasePool 的简单用法,但它无法处理复杂的条件情况,或者在新的 @autoreleasepool 的主体内定义变量并在其后使用的情况。
-
ARC 要求你在 init 方法中将 [super init] 的结果分配给 self。
以下在 ARC init 方法中无效:
[super init]; 复制代码
简单的解决方法是将其更改为:
self = [super init]; 复制代码
正确的解决方法是这样做,并在继续之前检查结果为 nil:
self = [super init]; if (self) { ... 复制代码
-
你无法实现自定义 retain 或 release 方法。
实现自定义 retain 或 release 方法会打破弱指针。想要提供自定义实现有几个常见原因:
-
性能。
请不要再这样做了; NSObject 的 retain 和 release 的实现现在要快得多。如果你仍然发现问题,请提交错误。
-
实现自定义弱指针系统。
请改用 __weak。
-
实现单例类。
请改用共享实例模式。或者,使用类而不是实例方法,这样就不必分配对象了。
-
-
“Assigned”实例变量变得 strong。
在 ARC 之前,实例变量是非拥有引用 - 直接将对象分配给实例变量并不延长对象的生命周期。为了使属性变强,你通常会实现或合成调用适当内存管理方法的访问器方法; 相反,你可能已经实现了以下示例中显示的访问器方法来维护弱属性。
@interface MyClass : Superclass { id thing; // Weak reference. } // ... @end @implementation MyClass - (id)thing { return thing; } - (void)setThing:(id)newThing { thing = newThing; } // ... @end 复制代码
对于 ARC,实例变量默认是强引用 - 将对象直接分配给实例变量会延长对象的生命周期。迁移工具无法确定实例变量何时弱。 要保持与以前相同的行为,必须将实例变量标记为弱,或使用声明的属性。
@interface MyClass : Superclass { id __weak thing; } // ... @end @implementation MyClass - (id)thing { return thing; } - (void)setThing:(id)newThing { thing = newThing; } // ... @end 复制代码
或:
@interface MyClass : Superclass @property (weak) id thing; // ... @end @implementation MyClass @synthesize thing; // ... @end 复制代码
-
你不能在 C 结构中使用 strong ids。
例如,以下代码将无法编译:
struct X { id x; float y; }; 复制代码
这是因为 x 默认 strong 引用,编译器无法安全地合成使其正常工作所需的所有代码。例如,如果通过一些最终执行自由的代码将指针传递给其中一个结构,则必须在释放结构之前释放每个 id。编译器无法可靠地执行此操作,因此在 ARC 模式下不允许完全禁用结构中的 strong ids。有几种可能的解决方案:
-
使用 Objective-C 对象而不是结构。
无论如何,这被认为是最佳实践。
-
如果使用 Objective-C 对象是次优的(可能你需要这些结构的密集数组),那么请考虑使用 void *。
这需要使用下面描述的显式强制转换。
-
将对象引用标记为 __unsafe_unretained。
这种方法对于这样的半常见模式可能很有用:
struct x { NSString *S; int X; } StaticArray[] = { @"foo", 42, @"bar, 97, ... }; 复制代码
你将结构声明为:
struct x { NSString * __unsafe_unretained S; int X; } 复制代码
如果对象可以从指针下面释放出来,这可能是有问题的并且是不安全的,但是对于已知永远像常量字符串文字一样的事物来说它非常有用。
-
-
你不能直接在 id 和 void * 之间进行转换(包括 Core Foundation 类型)。
这在 Managing Toll-Free Bridging 中有更详细的讨论。
经常问的问题
我如何看待 ARC?retains/releases 的位置在哪里?
尝试不再考虑 retain/release 调用的位置,而是考虑应用程序算法。考虑对象中的“强弱”指针,对象所有权以及可能的引用循环。
我还需要为我的对象编写 dealloc 方法吗?
也许。
由于 ARC 不会自动执行 malloc/free,管理 Core Foundation 对象,文件描述符等的生命周期,因此你仍然可以通过编写 dealloc 方法来释放这些资源。
你不必(实际上不能)释放实例变量,但你可能需要在系统类和其他未使用 ARC 编译的代码上调用 [self setDelegate:nil]。
ARC 中的 dealloc 方法不需要 - 或允许调用[super dealloc]; 链接到父类由运行时处理和强制执行。
ARC 中仍然有引用循环吗?
是。
ARC 自动 retain/release,并继承引用循环的问题。幸运的是,迁移到 ARC 的代码很少开始泄漏,因为属性已经声明属性是否 retaining。
blocks 如何在 ARC 中工作?
在 ARC 模式下向块传递块时块“正常工作”,例如在返回中。你不必再调用 Block Copy。
需要注意的一件事是 NSString * __block myString 保留在 ARC 模式下,而不是可能悬空的指针。要获取先前的行为,请使用 __block NSString * __unsafe_unretained myString 或(更好的是)使用 __block NSString * __weak myString。
我可以使用 Snow Leopard 为 ARC 开发 OS X 应用程序吗?
不可以。Xcode 4.2 的 Snow Leopard 版本在 OS X 上根本不支持 ARC,因为它不包括 10.7 SDK。Snow Leopard 的 Xcode 4.2 确实支持 ARC for iOS,而 Xcode 4.2 for Lion 支持 OS X 和 iOS。这意味着你需要 Lion 系统来构建在 Snow Leopard 上运行的 ARC 应用程序。
我可以在 ARC 下创建一个 retained 指针的C数组吗?
是的,你可以,如此示例所示:
// Note calloc() to get zero-filled memory. __strong SomeClass **dynamicArray = (__strong SomeClass **)calloc(entries, sizeof(SomeClass *)); for (int i = 0; i < entries; i++) { dynamicArray[i] = [[SomeClass alloc] init]; } // When you're done, set each entry to nil to tell ARC to release the object. for (int i = 0; i < entries; i++) { dynamicArray[i] = nil; } free(dynamicArray); 复制代码
有许多方面需要注意:
- 在某些情况下,你需要编写 __strong SomeClass **,因为默认值是 __autoreleasing SomeClass **。
- 分配的内存必须为零填充。
- 在释放数组之前,必须将每个元素设置为 nil(memset 或 bzero 将不起作用)。
- 你应该避免使用 memcpy 或 realloc。
ARC 慢吗?
这取决于你正在测量什么,但通常是“不”。编译器有效地消除了许多无关的 retain/release 调用,并且已经投入了大量精力来加速 Objective-C 运行时。特别是,当方法的调用者是 ARC 代码时,常见的“返回 retain/autoreleased 对象”模式要快得多,并且实际上并不将对象放入自动释放池中。
需要注意的一个问题是优化器不在常见的调试配置中运行,因此期望在-O0处看到比在-Os更多的 retain/release 流量。
ARC 是否在 ObjC++ 模式下工作?
是。你甚至可以在类和容器中放置 strong/weak idsD。ARC 编译器在复制构造函数和析构函数等中合成 retain/release 逻辑以使其工作。
哪些类不支持弱引用?
你当前无法创建对以下类的实例的弱引用:
NSATSTypesetter,NSColorSpace,NSFont,NSMenuView,NSParagraphStyle,NSSimpleHorizontalTypesetter 和 NSTextView。
注意:此外,在 OS X v10.7 中,你无法创建对 NSFontManager,NSFontPanel,NSImage,NSTableCellView,NSViewController,NSWindow 和 NSWindowController 实例的弱引用。此外,在 OS X v10.7中,AV Foundation 框架中的任何类都不支持弱引用。
对于声明的属性,你应该使用 assign 而不是 weak; 对于变量,你应该使用 __unsafe_unretained 而不是 __weak。
此外,你无法在 ARC 下从 NSHashTable,NSMapTable 或 NSPointerArray 的实例创建弱引用。
在对 NSCell 或使用 NSCopyObject 的其他类进行子类化时,我该怎么办?
没什么特别的。ARC 负责处理你必须明确添加额外 retains 的情况。使用 ARC,所有复制方法都应该只复制实例变量。
我可以选择退出 ARC 以获取特定文件吗?
可以。
迁移项目以使用 ARC 时,-fobjc-arc 编译器标志将设置为所有 Objective-C 源文件的缺省值。你可以使用该类的 -fno-objc-arc 编译器标志为特定类禁用 ARC。在 Xcode 中,在目标 Build Phases 选项卡中,打开 Compile Sources 组以显示源文件列表。双击要为其设置标志的文件,在弹出式面板中输入 -fno-objc-arc,然后单击“完成”。
是否在 Mac 上弃用了GC(垃圾收集)?
OS X Mountain Lion v10.8 中不推荐使用垃圾收集,并且将在 OS X 的未来版本中删除垃圾收集。自动引用计数是推荐的替代技术。为了帮助迁移现有应用程序,Xcode 4.3 及更高版本中的 ARC 迁移工具支持将垃圾收集的 OS X 应用程序迁移到 ARC。
注意:对于面向 Mac App Store 的应用,Apple 强烈建议你尽快使用 ARC 替换垃圾回收,因为 Mac App Store 指南禁止使用已弃用的技术。
以上所述就是小编给大家介绍的《ARC 时代的内存管理》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:- MRC 时代的内存管理
- 18 张图解密新时代内存分配器 TCMalloc
- BERT时代与后时代的NLP(一)
- BERT时代与后时代的NLP(二)
- 一文了解AI时代的数据风险(后真相时代、算法囚徒和权利让渡)
- 航盛电子朱新军:智能座舱从互联网时代迈入AI时代
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。