jtb*_*des 6 syntax memory-management objective-c ownership automatic-ref-counting
在ARC下,out-parameter采用以下形式(默认情况下;这相当于NSError **):
- (BOOL)tryWithError:(NSError *__autoreleasing *)err;
Run Code Online (Sandbox Code Playgroud)
从Transitioning to ARC Release Notes,如果我们传递__strong局部变量的地址,编译器将创建一个临时变量并生成以下代码:
NSError *error; // strong
BOOL ok = [myObject tryWithError:&error];
// translated to
NSError *__strong error;
NSError *__autoreleasing tmp = error;
BOOL ok = [myObject tryWithError:&tmp];
error = tmp;
Run Code Online (Sandbox Code Playgroud)
但是如果我们用一个实例变量来做:
@implementation Foo {
NSError *_error; // strong
}
- (void)bar
{
[myObject tryWithError:&_error];
}
...
Run Code Online (Sandbox Code Playgroud)
这给了我们错误
将非本地对象的地址传递给
__autoreleasing参数以进行回写.
为什么这个无效?编译器是否只能自动将此类代码转换为此?
- (void)bar
{
NSError *__autoreleasing tmp = _error;
[myObject tryWithError:&tmp];
_error = tmp;
}
Run Code Online (Sandbox Code Playgroud)
毕竟,这就是我将要写的解决问题的方法!
注意:将out关键字添加到参数类型将略微减少编译器的工作量,因为它不必将当前值读入临时变量 - 但这不会解决错误.
指向 ivar 的指针无法在 ARC 下传递给 \xe2\x80\x9cid __autoreleasing *\xe2\x80\x9d 参数,因为这种传递写回的格式不正确。ARC规范中的相应部分列出了pass-by writeback的合法形式,这里唯一适用的是
\n\n\n\n\n&var,其中 var 是具有可保留对象的自动存储持续时间的标量变量\n
\n
,因此只允许自动存储持续时间(局部变量)。
\n\n为什么这是无效的:我很确定这里的原因是与旧代码的兼容性:
\n\n1)你应该只看失败情况下的错误写回。在成功的情况下,根本无法保证错误指针内的内容。
\n\n2) 一般来说,是否使用writeback值取决于方法的约定。这是编译器无法检查的。
\n\n&error这是将( NSError * __autoreleasing *) 类型与写回类型(NSError **解释为)相匹配的代码版本NSError * __autoreleasing *。如果ok为YES,则不会触及错误值。
NSError * __autoreleasing error;\nBOOL OK = [myObject performOperationWithError:&error];\nif (!OK) {\n // use error\n}\nRun Code Online (Sandbox Code Playgroud)\n\n然而,这些__autoreleasing都很丑陋,所以编译器并__autoreleasing允许我们传递一个__strong(但本地的)变量(默认所有权),而不是强迫我们到处使用:
NSError *error;\nBOOL OK = [myObject performOperationWithError:&error];\nif (!OK) {\n // use error\n}\nRun Code Online (Sandbox Code Playgroud)\n\n根据文档,它被重写为:
\n\nNSError * __strong error;\nNSError * __autoreleasing tmp = error;\nBOOL OK = [myObject performOperationWithError:&tmp];\nerror = tmp;\nif (!OK) {\n // use error\n}\nRun Code Online (Sandbox Code Playgroud)\n\n完全不是问题,错误只会在成功的情况下使用。
\n\n现在让我们看一下__strong实例变量_error。为什么编译器不允许这样做?重写后的样子如下:
NSError * __autoreleasing tmp = _error;\nBOOL OK = [myObject performOperationWithError:&tmp];\n_error = tmp;\nif (!OK) {\n // use error\n}\nRun Code Online (Sandbox Code Playgroud)\n\n这里的问题是,写回总是tmp会被使用(分配给实例变量),忽略了写回只能在错误情况下使用的方法的约定(或者一般来说,无论该方法的文档说什么)。将最后一个错误分配给实例变量的安全方法是_error
NSError * __autoreleasing tmp = _error;\nBOOL OK = [myObject performOperationWithError:&tmp];\nif (!OK) {\n _error = tmp; \n // use error\n} else {\n _error = nil; // Make sure that _error is nil if there was no error.\n}\nRun Code Online (Sandbox Code Playgroud)\n\n这仅适用于返回错误的 Cocoa 方法的约定。一般来说,编译器无法告诉方法将如何处理id *:可能有使用不同约定的旧方法。因此,如果您确实想将写回存储在__strong实例变量中,那么您目前必须自己多走一英里,而且我不希望这种情况发生改变。
| 归档时间: |
|
| 查看次数: |
1272 次 |
| 最近记录: |