Objective-C中的in,out,inout,byref,byval等是什么?它们代表什么意思?

67

阅读Objective-C手册中的@encoding时,我发现了一些陌生的东西。

Table 6-2  Objective-C method encodings
Code Meaning
r    const
n    in
N    inout
o    out
O    bycopy
R    byref
V    oneway

我唯一知道的是 oneway,其他的有哪些?

4个回答

88

这些是分布式对象使用的方法参数和返回值注释。我说“使用过”,因为显然在苹果的文档中已经没有它们的踪迹了。以前在Objective-C编程语言文档中有一个远程消息传递部分,现在仍然被分布式对象编程主题文档引用。

  • in:参数仅为输入参数,不会在后面被引用
  • out:参数仅为输出参数,用于通过引用返回值
  • inout:参数既是输入参数又是输出参数
  • const:(指针)参数是常量
  • bycopy:不使用代理/NSDistantObject,而是传递或返回对象的副本
  • byref:使用代理对象(默认)

54
就此而言,苹果在新的UIScrollViewDelegate方法中使用了inout (targetContentOffset:(inout CGPoint *)targetContentOffset)。这就是我来这里的原因。 - Mazyod
6
其实我也这么认为。如果他们可以使用inout,为什么要做像双重指针这样复杂的事情来获取错误呢?实际上,既然他们传递的是CGPOINT *,他们根本不需要指定inout。这是一个指针,CGPOINT是一个结构体。只要将新的CGPOINT放在targetContentOffset所指向的地址中,就没问题了。 - Anonymous White
1
NSDateFormatter.h 中有更多的参考资料。 - João Nunes
1
苹果在验证键的值时使用了 inout 和 out。-(BOOL)validateValue:(inout __autoreleasing id *)ioValue forKey:(NSString *)inKey error:(out NSError *__autoreleasing *)outError - Vishal Singh
"inout"也在UIPopoverViewController中使用:-popoverController:willRepositionPopoverToRect:inView: - matm
显示剩余2条评论

27
除了分布式对象,其中一个注释似乎被ARC所使用。我在clang的通过写回传递到输出参数的描述中发现了以下内容:
“如果该参数不是Objective-C方法参数,并标记为out,则会读取*p,并使用基本语义将结果写入临时变量。”
这与像- (BOOL)executeWithError:(out NSError **)error这样的方法有关。
忽略out关键字,ARC有一个明确定义的行为,将按引用对象传递视为__autoreleasing处理,因此ARC将error参数视为NSError * __autoreleasing *类型。如果您使用另外限定的变量,ARC会在函数中添加一个临时的自动释放变量传递(为了一致性):

原始代码

NSError *error;
[obj executeWithError:&error];

伪代码转换
NSError * __strong error;
NSError * __autoreleasing temp;
temp = error;
[obj executeWithError:&temp];
error = temp;

使用上述代码,如果我们能够知道temp永远不会被读取,那么temp = error这一行将是不必要的。这就是out注释发挥作用的地方。根据引用描述,如果缺少out,编译器必须添加temp = error这一行,但如果它包含out,则可以排除该行并使代码变得更小/更快。使用out,转换后的代码变为:

NSError * __strong error;
NSError * __autoreleasing temp;
[obj executeWithError:&temp];
error = temp;

当然,如果您非常担心二进制大小和速度,您应该编写以下代码:
NSError * __autoreleasing error;
[obj executeWithError:&error];

“这些注解很可能在编译器和运行时的其他地方使用,并且将来可能会在更多地方使用。个人而言,我喜欢使用out作为向其他开发人员暗示我不会读取该值的提示。”

似乎原始代码缺少一个取地址运算符。executeWithError:&error]; - eonil
@BrianNickel,所以(out NSError **)和(NSError * __autoreleasing *)是一样的吗? - denis631
3
您IP地址为143.198.54.68,由于运营成本限制,当前对于免费用户的使用频率限制为每个IP每72小时10次对话,如需解除限制,请点击左下角设置图标按钮(手机用户先点击左上角菜单按钮)。 - Brian Nickel
它只是删除了那一行。我会更新答案以澄清。 - Brian Nickel
@denis631 这是可选的、晦涩的,在大局中节省的东西微不足道,几乎没有人需要它。 - Brian Nickel
显示剩余5条评论

0
如果有人偶然看到这篇文章并且和我一样感到困惑,'in' 参数也可以是一个代表快速枚举的关键字。请参考这里获取更多细节。

在其他当前语言中,如Java和Python中,这是一个常见的结构,但在Obj-C中几乎从未使用过。个人而言,当我需要这种东西时,我倾向于使用blockEnumerators,即使这需要更多的打字...我不知道,我觉得任何阅读我的代码的人更有可能立即理解它。 - ArtOfWarfare

-3

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接