迁移至ARC版本说明(Transitioning to ARC Release Notes)

2017-01-14 10:21:39来源:http://www.jianshu.com/p/923a85fbb1c2作者:杨浩宇人点击

迁移至ARC版本说明

自动引用计数(ARC)是编译器的一个特色,提供了Objective-C对象的自动内存管理机制。比起不得不考虑retain和release操作,ARC让你更加专注于应用中那些有趣的代码,如对象图,对象关系。




摘要

通过在编译时添加代码的方式,ARC保证所有对象按需存在,按需释放。从概念上来讲,它与手动引用计数(参见Advanced Memory Management Programming Guide)有着相同的内存管理约定,二者都会为你添加合适的内存管理方法调用。


为了编译器能生成正确的代码,ARC限定了你可以使用的一些方法,以及toll-free桥接的使用方式(参见“Toll-Free Bridged Types”)。与此同时ARC还为对象引用和声明式属性引进了新的生命周期限定符。


ARC适用于OS X v10.6和v10.7(64位)下的Xcode4.2,以及iOS 4和iOS 5。OS X v10.6和iOS 4不支持弱引用。


Xcode提供了自动化的工具,完成ARC转换过程中需要手工操作的部分(例如删除retain和release方法调用),并且帮助你在迁移过程中不能自动完成的操作(选择Edit->Refactor->Convert to Objective-C ARC)。迁移工具将工程中的所有文件使用ARC进行转换。如果你觉得在某些文件中使用手动引用计数会更方便,那么你也可以选择在单独文件中使用MRC。


参见:


Advanced Memory Management Programming Guide
Memory Management Programming Guide for Core Foundation
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

(对象属性(properties)默认是强类型的strong;strong属性描述于“ARC Introduces New Lifetime Qualifiers.”)


使用ARC,你可以如下实现一个contrived方法:


- (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保证oldLastName在NSLog语句之前不会被释放。


ARC强制执行新规则

为了正常运转,ARC使用了一些在使用其它编译模式下没有的新规则。这些规则意在提供完全可靠的内存管理模型;在某些情况下,它们仅使用最佳实践方法,在其它情况下,它们仅简化你的代码或明显的做出推论告知你不需要处理内存管理。如果你违反了这些规则,你会马上得到一个编译时错误,而不是在运行时可能会显现的一个狡猾的bug。



不能显式的调用dealloc,实现或调用retain,release,retainCount,autorelease。
同样也不能使用@selector(retain), @selector(release), 等等类似的选择器。
如果你需要管理资源而不是释放实例变量,那你可以实现dealloc方法。你不需要(事实上你不能)释放实例变量,但你可能需要在系统类和其它的未使用ARC代码中调用[systemClassInstance setDelegate:nil]方法。
在ARC中自定义的dealloc方法不要调用[super dealloc]方法(它实际上会导致编译器错误)。到super的链式调用是自动的并且是编译器强制执行的。
你仍可以在Core Foundation样式的的对象上,使CFRetain,CFRelease,和其它相关的函数(参见Managing Toll-Free Bridging)。



你不能使用NSAllocateObject或NSDeallocateObject
你使用alloc来创建对象;运行时系统会注意释放这些对象。



你不能在C语言结构体中使用对象指针。
与其使用一个结构体,不如创建一个Objective-C类来管理数据。



id与void之间不能随意转换
你必须使用特定的类型转换来告诉编译器对象的生命周期。你需要在Objective-C对象和以函数参数传入的Core Foundation类型值之间进行这样的转换。有关详情,参见“Managing Toll-Free Bridging”。



你不能使用NSAutoreleasePool对象
ARC提供了@autoreleasepool来代替。这比NSAutoreleasePool更高效。



你不能使用内存区
再也没有使用NSZone的必要了——现代的Objective-C运行时会永远忽略它。



为了允许与手动retain-release的代码进行交互,ARC在方法命名上加上了一个约束:


你不能以new为开头命名一个访问器的名字。这反过来意味着你不能声明一个以new开头的属性,除非你指定一个不同名称的getter方法:
// Won't work:
@property NSString *newTitle;
// Works:
@property (getter=theNewTitle) NSString *newTitle;

ARC引入了新的生命周期限定符

ARC为对象引入了几种新的生命周期限定符,以及弱类型引用。弱类型应用不会延长它所指向对象的生命周期,一旦对象没有强引用指向对象时,弱引用会自动变为nil。


在程序中,你应该充分利用这些限定符来管理对象图。尤其是,ARC不能阻止强引用循环(strong reference cycles,之前称为retain cycles,参“Practical Memory Management”)的发生。审慎的使用弱类型关系会帮助你避免创建强引用循环。


Property的属性

weak和strong关键字是新引入的property声明属性,如下例所示:


// 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。如果它所指向的对象已经被释放,那么它会成为一个野指针。



__autoreleasing用以指示以引用(id*)传入的参数并在return后自动释放。



你应该正确的修饰变量。在对象变量的声明时使用限定符的正确格式为:


ClassName * qualifier variableName;

例如:


MyClass * __weak myWeakReference;
MyClass * __unsafe_unretained myUnsafeReference;

从技术上讲其它的变体写法都是错误的,但编译器都会”宽恕“它们。要弄清该问题,参见http://cdecl.org/。


在堆栈上使用__weak变量时要当心。考虑以下的例子:


NSString * __weak string = [[NSString alloc] initWithFormat:@"First Name: %@", [self firstName]];
NSLog(@"string: %@", string);

虽然string是在初始化赋值之后使用,但是在赋值的时候并没有其它强引用指向字符串对象;因此字符串对象会马上释放掉。log语句显示stirng的值为null。(编译器对这种情况会提示警告)


你也要注意通过引用方式传入的对象。以下代码会正常运转:


NSError *error;
BOOL OK = [myObject performOperationWithError:&error];
if (!OK) {
// Report the error.
// ...

而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。


使用生命周期限定符来避免强引用循环

你可以使用生命周期限定符来避免强循环引用。例如,通常如果你的对象图形成于父-子层级结构中,父对象需要引用它的子对象,反之亦然,那么你构造parent-to-child的关系为强类型,child-to-parent的关系为弱类型。其它情况可能会更加微妙,尤其是在涉及到block对象时。


在MRC的模式下, __block id x,不会保留x。在ARC模式下,__block id x;默认会保留x(就像其它值一样)。你可以使用unsafeunretained __block id x ;然而,就像__unsafe_unretained名字蕴含的那样,拥有一个未保留变量是危险的(因为他可能是一个野指针),因此最好不要使用。有两个更好的选择是要么使用__weak(如果你不需要支持iOS 4或OS X v10.6),要么设置__block值nil来打破循环引用。


以下的代码片段说明了在MRC下时常会使用的模式。


MyViewController *myController = [[MyViewController alloc] init…];
// ...
myController.completionHandler = ^(NSInteger result) {
[myController dismissViewControllerAnimated:YES completion:nil];
};
[self presentViewController:myController animated:YES completion:^{
[myController release];
}];

如上所属,你可以使用__block限定符来替代,并在completion处理方法中将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];
};

而对于特殊的循环,你应该使用:


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。但这也不适用于特殊的循环,因为在实际问题中验证__unsafe_unretained指针是否仍有效或是否仍指向相同的对象,是非常困难或根本不可能实现的。


ARC使用新声明来管理自动释放池

使用ARC,你不能直接使用NSAutoreleasePool类来管理自动释放池。相反,你需要使用@autoreleasepoo块:


@autoreleasepool {
// Code, such as a loop that creates a large number of temporary objects.
}

这个简单的结构让编译器来判断引用计数的状态。在入口,自动释放池会被push。在正常退出(break, return, goto, fall-through,等等)自动释放池会被pop。出于对已有代码兼容性的考虑,如果因异常导致退出,自动释放池将不会被pop。


该语法在所有Objective-C模式下都可用。相比使用NSAutoreleasePool类来说, @autoreleasepool更加高效;因此鼓励你在使用NSAutoreleasePool的地方使用@autoreleasepool。


跨平台下Outlet管理保持一致的模式

ARC下的iOS和OS X中声明outlets的模式已经发生变化,并且在跨平台下保持一致性。你通常应该接受的是:outlets应该是weak的,除了那些在nib文件(或storyboard屏)中File‘s Owner指向的顶级对象应该是strong的。


Resource Programming Guide中的“Nib Files”做出了全面的解释。


栈变量会初始化为nil

使用ARC,strong,weak,以及autoreleasing的栈变量现在会隐式的初始化为nil,例如:


- (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及早期版本的Xcode不支持ARC。


管理Toll-Free桥接

在许多Cocoa应用中,你可以使用Core Foundation样式的对象,不管是来自于Core Foundation框架本身(例如,CFArrayRef或CFMutableDictionaryRef),还是来自于诸如Core Graphics一样采用Core Foundation约定的框架(你可能使用向CGColorSpaceRef和CGGradientRef)样式的类型)。


编译器不会自动管理Core Foundation对象的生命周期;你必须调用符合Core Foundation内存管理规则的CFRetain和CFRelease方法(或者合适的特殊类型变体)来释放对象。(参见Memory Management Programming Guide for Core Foundation)。


如果你在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对象

编译器了解Objective-C的那些沿用Cocoa命名规则返回Core Foundation类型的方法(参见Advanced Memory Management Programming Guide)。例如,编译器知道,在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的内存管理规则中都已近说明了(参见Memory Management Programming Guide for 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{}结构代替。这在你的自动释放池中强制使用block结构,并且比NSAutoreleasePool要快六倍。即使在非ARC的代码中@autoreleasepool也能工作。因为@autoreleasepool较NSAutoreleasePool要快得多,所以许多旧的”性能hacks“会无条件的被@autoreleasepool所替代。
迁移器只处理NSAutoreleasePool的简单用法,不能处理复杂条件下的情况,或者一个定义在新的@autoreleasepool结构内部的变量并在其之外使用的情况。
ACR需要你将在init方法中[super init]的结果赋值给self。
下面的代码在ARC的init方法中是不合法的:
[super init];

简单的修正是做如下变换:
self = [super init];

更全面的改法是在继续之前检测结果是否为nil:
self = [super init];
if (self) {
...

不能实现自定义的retain和release方法
实现自定义的retain和release方法会打破弱引用。有几种常见原因是想要提供提供自定义实现的:
1.性能
请不要再这么做了;NSObject的retain和release现在更加快捷。如果你仍发现问题,请提交bug。
2.实现自定义的弱指针系统
使用__weak代替
3.实现单例类
使用共享示例代替。或使用类方法类替代实例方法,这避免了一直都要去分配对象空间的操作。

"Assigned"实例变量成为了strong类型
在ARC之前,实例变量是非拥有引用(non-owning redernces)——直接将对象赋值给实例变量不会扩展对象的生命周期。为了令属性成为强类型,你通常只要实现或合成访问器方法,它们会调用合适的内存管理方法;相比较而言,你可能已经如下例子中实现了访问器方法来维护一个弱类型属性。


@interface MyClass : Superclass {
id thing; // Weak reference.
}
// ...
@end
@implementation MyClass
- (id)thing {
return thing;
}
- (void)setThing:(id)newThing {
thing = newThing;
}
// ...
@end

使用ARC,实例变量默认是强类型引用——将实例变量直接赋值给对象的确会扩展对象的生命周期。迁移工具没办法决定实例变量何时应该是weak类型的。为了像之前那样维护同样的行为,你必须将实例变量标记为weak类型,或使用一个声明式属性。


@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语言结构体重不能使用强类型的ids,
例如,以下代码会编译不过
struct X { id x; float y; };

因为x默认肯定是被保留的,编译器无法安全的合成所有保证代码正常运转所需的所有代码。例如,如果你通过一些最终会被释放的代码来传入一个指针到这些结构体后,每个id在结构体回收之前会被被迫释放掉。编译器不能可靠的做到这点,所以在结构体中的强类型的ids在ARC模式下是完全无效的。以下有几个可能的解决办法:
1.使用Objective-C对象代替结构体
这是最好的实践方法。
2.如果使用Objective-C对象是次优方案,(可能你想要这些结构体组成的一个数组)那么考虑void *进行替代。
这需要使用显示的类型转换,在下面会提到。
3.将对象引用标记为__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?它把retians/releases放在哪里呢?


尝试不要再考虑retain/release应该放在哪,要考虑你应用的逻辑。考虑你对象中的”strong和weak“指针,对象的所有权,可能的循环引用。


我是否还需要为我的对象编写dealloc方法?


可能需要。


因为ARC不会自动操作malloc/free,Core Foundation对象的生命周期管理,文件描述,等等。你仍需要在dealloc方法中释放这样的资源。


你不需要(实际根本不能)释放实例变量,但是你需要在系统类和其它未使用ARC编译的代码上调用[self setDelegate:nil]。


ARC中的dealloc方法不需要或不允许调用[super dealloc];到super的链式结构是在运行时进行处理和实施的。


在ARC中仍存在循环引用吗?


是的。


ARC自动处理retain/release,并且继承了循环引用的问题。幸运的是,迁移到ARC的代码很少内存泄露,因为属性(property)已经声明了是否要保留。


block在ARC中是怎样工作的呢


block在你传递和返回的时候就开始“工作”了。你不再需要调用Block Copy了。


你需要注意的是,NSString * __block myString在ARC模式下是会保留的,可能会造成野指针错误。为防止这样的事情发生,使用block NSString * unsafe_unretained myString
或者 (更好) 使用block NSString * weak myString来替代。


我可以在OS X Snow Leopard上使用ARC来编写应用程序吗


不行。Snow Leopard平台上的Xcode 4.2在全平台的OS X上都不支持ARC,因为它不包含10.7的SDK。Snow Leopard的Xcode 4.2不支持OS X和iOS的ARC,而Lion上的Xcode 4.2 OS X和iOS上的ARC都支持。这意味着你需要升级到Lion系统来对应用进行ARC的支持。


在ARC下我能创建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 **。
分配的内存必须是零填充的
你必须在释放数组(memset或bzero无法工作)之前将每个元素设置为nil.
避免使用memcpy或realloc

ARC运行速度会慢吗?


这取决于你的测量方式,但基本”很快“。编译器高效的消除许多外部的retian和release调用,而且总的来说会更加关注于提升Objective-C运行时的速度。尤其是,当调用者是ARC代码时,常用的"返回一个retain/autoreleased对象"模式会更快速而且实际上并没有将对象放入到自动释放池中。


需要注意的是优化器不是在常规的配置下运行的,所以可以看到很多的retain/release traffic at -O0than at -Os。


ARC支持Objective-C++吗


是的。你也可以在类和容器中使用strong或weak的ids。ARC的编译器会在构造函数和析构函数中处理这些逻辑。


哪些类不支持弱引用


在如下的这些类里你不能直接使用弱引用:


NSATSTypesetter, NSColorSpace, NSFont, NSMenuView, NSParagraphStyle, NSSimpleHorizontalTypesetter, 和NSTextView。


注意:另外,在OS X v10.7你不能创建NSFontManager, NSFontPanel, NSImage, NSTableCellView, NSViewController
,NSWindow, 和NSWindowController的弱引用实例。还有,在OS X v10.7中AVFoundation框架支持弱引用。


对于声明的property,你应当使用assign代替weak;对于变量,你应当使用unsafe_unretained代替weak。


此外,你不能为ARC环境下的NSHashTable, NSMapTable, 或NSPointerArray创建弱引用实例。


在使用NSCell或其他的NSCopyObject子类的时候应该怎么做

没什么特别的。ARC会帮你管理添加额外的retain。通过ARC,所有的copy都会直接copy实例变量。



我可以在特定文件下退出ARC吗?

可以。


在你迁移工程来使用ARC时,-fobjc-arc编译器标记默认会设置到每个Objective-C的源文件。你可以使用-fno-objc-arc编译器标记来在特定的类中禁用ARC。在Xcode中,在target的 Build Phases中,打开 Compile Sources 组显示源文件列表。双击你想要设置标记的文件,在pop-up面板中输入-fno-objc-arc指定,之后点击完成。




GC(垃圾回收)会在Mac上被废除吗

垃圾回收在OS X Mountain Lion v10.8上被标记为不建议使用,并会在未来的某个版本中进行移除。自动引用计数是用来替代的科技。为了适应现在还存在的应用,Xcode 4.3中的工具会支持从垃圾回收迁移到ARC。


注意:对于已经上线的Mac应用,我们强烈建议尽快替换为ARC,因为Mac App Store guidelines(参见Mac App Store Review Guidelines)禁止应用中使用过期的技术。




最新文章

123

最新摄影

微信扫一扫

第七城市微信公众平台