我拼命想要了解__autoreleasing
关键字的用法Objective-C
.我已经彻底阅读了以下问题的答案:
在哪些情况下我们需要在ARC下编写__autoreleasing所有权限定符?
在代码段示例中使用__autoreleasing
NSError和__autoreleasing
尽管现在我明白我仍然无法得到主要的东西,目的.为什么这样?让我解释一下究竟让我困惑的是什么.考虑一下代码:
@interface MyError : NSError @end @implementation MyError - (void)dealloc { NSLog(@"My error dealloc"); } @end @interface ErrorHandler : NSObject - (void)handleError:(MyError* __strong*)error; @end @implementation ErrorHandler - (void)handleError:(MyError* __strong*)error { *error = [[MyError alloc] initWithDomain:@"Blabla" code:100500 userInfo:@{ NSLocalizedDescriptionKey : @"TestDescription" }]; } @end - (void)test { MyError *error = nil; ErrorHandler *handler = [ErrorHandler new]; [handler handleError:&error]; NSLog(@"Localized description %@", error.localizedDescription); }
我写了这段代码,看看如果我不使用会发生什么__autoreleasing
.如您所见,handleError
方法接受对显式声明为的引用的引用__strong
.没有任何反应.一切都好.我能够从MyError
对象获取信息,并且已经成功解除分配,我明白了.如果我把__autoreleasing
而不是__strong
什么改变.那么为什么要使用__autoreleasing
它什么都不改变?这是我不明白的.谁能告诉我我错过了什么?感谢大家
我认为tl; dr的答案是通过声明参数,因为__autoreleasing
如果你愿意,你也可以传递指向弱引用的指针.
想象一下你的方法如下:
-(void) handleError: (NSError* __strong *) error { NSError* myError = [[NSError alloc] init]; *error = myError; }
编译器认为这*error
很强,所以当它完成赋值时,你得到+1保留计数.在编译器完成代码之后,它看起来像这样:
-(void) handleError: (NSError* __strong *) error { NSError* myError = [[NSError alloc] init]; *error = [myError retain]; [myError release]; }
所以,如果你这样称呼它:
NSError* error; // strong reference [self handleError: &error];
一切都很好,因为编译器会在范围的末尾正确地发布版本.如果你这样做:
NSError* __weak error; // weak reference [self handleError: &error];
它可能不会编译,但如果确实如此,因为编译器认为引用很弱(它看不到强大的赋值handleError:
),它就不会放入一个版本,对象就会泄漏.
如果您定义这样的方法:
-(void) handleError: (NSError* __weak *) error { NSError* myError = [[NSError alloc] init]; *error = myError; }
编译器添加代码,如下所示:
-(void) handleError: (NSError* __weak *) error { NSError* myError = [[NSError alloc] init]; *error = myError; [myError release]; }
更糟糕的是因为赋值*error
给了+0保留计数,这意味着,一旦myError
超出范围,即当方法返回时,它指向的对象就会被释放.
如果你这样做:
-(void) handleError: (NSError* __autoreleasing *) error { NSError* myError = [[NSError alloc] init]; *error = myError; }
编译器执行此操作:
-(void) handleError: (NSError* __autoreleasing *) error { NSError* myError = [[NSError alloc] init]; *error = [[myError retain] autorelease]; [myError release]; }
与前一种情况相同,但返回的对象位于方法末尾的自动释放池中,因此不会取消分配.因此,您可以error
在调用者中声明为强或弱,并且编译器有机会对返回的引用做一些合理的事情.
至少我认为这就是问题所在.