下面的 iOS 代码安全吗? (__autoreleasing 语义)

Posted

技术标签:

【中文标题】下面的 iOS 代码安全吗? (__autoreleasing 语义)【英文标题】:Is the following iOS code safe? (__autoreleasing semantics) 【发布时间】:2013-03-18 21:16:09 【问题描述】:
-(NSData *)jsonRepresentation:(NSError **error)error 
   NSDictionary *dict = [self getDictRepresentation];
   return [NSJSONSerialization dataWithJSONObject:dict options:nil error:error];


// Some other place...

NSError *__autoreleasing error = nil;
NSData *json = [obj jsonRepresentation:&error];

自动释放语义是否安全地将error 向上传递到我的第二个代码块?

【问题讨论】:

这些自动释放机制实际上是为局部变量隐含的(除了少数例外),不需要明确说明。但是,是的,它是正确的。 @RichardJ.RossIII:你什么意思? obj-c 类型的局部变量默认为__strong,除非另有说明。 @KevinBallard 我的意思是,只要它们可以延长声明它们的块的生命周期,它们的行为就像一个自动释放值。特别是返回值变成 __autoreleasing(当然,除非您指定另一个返回类型属性)。在极少数情况下真正需要 __autoreleasing。 @RichardJ.RossIII:我不确定你想说什么。方法的返回值根本不是所有权限定的。相反,它们被认为是“保留的返回值”或“未保留的返回值”,在后一种情况下,ARC 只保证对象将在调用边界上存活。这可能涉及将其放入自动释放池中,也可能不。 【参考方案1】:

根据the clang ARC spec,NSError ** 形式的方法参数(或者更确切地说,指向任何 obj-c 对象的指针)被隐式假定为NSError * __autoreleasing *。这意味着错误将在方法中自动释放。

至于调用站点,如果您使用 __autoreleasing 变量调用它,就像您所做的那样,那么一切都很好。事实上,我推荐这种模式。但是,如果您使用 __strong 变量调用它,它仍然可以工作。在这种情况下,编译器将生成一个未命名的__autoreleasing 临时地址,将其地址传递给方法,然后在返回时,将临时地址分配给__strong。所以如果你有

NSError *foo;
[bar callMethodWithError:&foo];

编译器会将其视为

NSError *foo;
NSError * __autoreleasing tmp = foo;
[bar callMethodWithError:&tmp];
foo = tmp;

It's actually slightly more complicated than that 如果输出参数被标记为out,但这通常是它的工作原理。

【讨论】:

【参考方案2】:

是的,它是正确的,但是你应该在方法声明中指定这个修饰符,而不是在变量的声明中。甚至 Apple 的官方文档也明确提到了这种情况:

__autoreleasing 用于表示通过引用 (id *) 传递并在返回时自动释放的参数。

【讨论】:

请注意,您应该在方法声明本身上指定__autoreleasing,而不是方法的参数。 @RichardJ.RossIII 谢谢,也添加了。

以上是关于下面的 iOS 代码安全吗? (__autoreleasing 语义)的主要内容,如果未能解决你的问题,请参考以下文章

[iOS开发]@autoreleasepool原理探究

在同一个语句中使用 shift 和 @_ 是不是安全?

线程的那点事情

Block使有注意点

$_POST 真的安全吗?

我可以在 iOS 中的代码中创建一个断点,比如 VC++ 上的 `__asmint 3`,然后在它被命中后继续执行吗?