非正式协议有什么需要

非正式协议有什么需要

本文介绍了非正式协议有什么需要?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经阅读了Apple文档网站上有关正式和非正式协议的在线文档,但是我错过了有关非正式协议的要点。我的意思是,

I've read the online docs about formal and informal protocols on Apple's documentation site, but I missed the point about informal protocols. I mean,


  1. 一个类不能符合非正式协议,因为默认情况下非正式协议几乎总是NSObject的类别,所以默认情况下符合该协议类。

  2. 如果要实现非正式协议,则必须在接口文件中重新声明要实现的方法。

  3. 另一个类无法检查您是否符合非正式协议(该类必须检查它是否对某些选择器做出了响应,但是不需要非正式协议也可以执行此操作)。 / li>
  1. a class cannot conform to an informal protocol, it conforms to it by default since informal protocols are almost always categories of the NSObject class.
  2. If you want to implement an informal protocol, you must redeclare the methods you want to implement in your interface file.
  3. Another class cannot check if you conform to the informal protocol (the class must check if it responds to some selectors, but the same can be done without the need of an informal protocol).

那么,拥有非正式协议的意义何在?鉴于以上三点,并且如果没有它们,您也可以做同样的事情,我真不明白它们在什么地方有用。我确定我会丢失一些东西,也许您可​​以帮忙。

So, what's the point of having an informal protocol? I can't really understand where they could be useful given the three points above and given that you could do the same things without them. I'm sure I'm missing something, maybe you can help.

编辑:过了一会儿,我仍然不明白为什么使用非正式协议,除了逻辑观点,即将一些方法组合在一起。知道吗?

after a while, I still do not see why informal protocols where used, apart from a logical point of view, i.e. group together some methods. Any idea?

推荐答案

您已经将一组相关方法分组在一起。非正式协议列出了如果类需要符合该非正式协议的方法(可选方法)。

You’ve got the grouping together a set of related methods part right. An informal protocol lists which (optional) methods can be implemented if a class needs to ‘conform’ to that informal protocol.

另一个原因是编译器和目标平台ABI。考虑一个委托类,其对象接受委托。在内部,委托类中的方法将执行以下操作:

The other reason is the compiler and the target platform ABI. Consider a delegating class whose objects accept a delegate. Internally, methods in the delegating class would do something like:

id delegate;

…

if ([_delegate respondsToSelector:@selector(someMethod:hey:ho:)]) {
    [_delegate someMethod:42 hey:@"hey" ho:@"ho, let's go"];
}

如果没有非正式协议,编译器将为上面的摘录发出警告,因为它会不会知道 someMethod:hey:ho:存在,其返回类型和参数类型。更重要的是,在不知道方法签名的情况下,编译器将不得不猜测返回类型和参数类型以准备调用站点,而这种猜测很可能是不匹配的。

Without an informal protocol, the compiler would emit warnings for the excerpt above because it wouldn’t be aware that someMethod:hey:ho: exists, its return type and its parameter types. More importantly, without knowing the method signature, the compiler would have to guess the return type and the argument types in order to prepare the call site, and this guess could very well be a mismatch.

例如,查看编译器上方摘录中发送的消息,可能会猜测该方法接受一个整数,一个NSString和另一个NSString作为参数。但是,如果该方法最初应该接受浮点数作为第一个参数,该怎么办?传递整数参数(在这种情况下,该参数存储在标准寄存器中)与传递64位浮点参数(在这种情况下,SSE寄存器)不同。如果该方法实际上支持最后一个参数中的变量参数而不是单个字符串,该怎么办?编译器不会相应地准备调用站点,否则将导致崩溃。

For example, looking at the message being sent in the excerpt above the compiler could guess that the method accepts an integer, an NSString, and another NSString as arguments. But what if the method is originally supposed to accept a floating point number as the first argument? Passing an integer argument (in this case, the argument is stored in a standard register) is different from passing a 64-bit floating point argument (in this case, a SSE register). And what if the method actually supports variable arguments in the last argument instead of a single string? The compiler wouldn’t prepare the call site accordingly, which would lead to crashes.

生成上面摘录的汇编有助于说明此问题:

Generating the assembly of the excerpt above helps illustrate this problem:

movl    $42, %edx
leaq    L__unnamed_cfstring_(%rip), %rax
leaq    L__unnamed_cfstring_3(%rip), %rcx
movq    -16(%rbp), %rdi
movq    L_OBJC_SELECTOR_REFERENCES_(%rip), %rsi
movq    %rcx, -24(%rbp)
movq    %rax, %rcx
movq    -24(%rbp), %r8
callq   _objc_msgSend

As您可以看到,42存储在寄存器EDX中。

As you can see, 42 was stored in register EDX.

但是,如果我们添加一个非正式协议,说明第一个参数的类型为 float

However, if we add an informal protocol stating that the first parameter is of type float:

@interface NSObject (DelegateInformalProtocol)
- (id)someMethod:(float)number hey:(id)hey ho:(id)ho;
@end

然后编译器以不同的方式准备调用站点:

then the compiler prepares the call site differently:

movabsq $42, %rax
cvtsi2ssq   %rax, %xmm0
leaq    L__unnamed_cfstring_(%rip), %rax
leaq    L__unnamed_cfstring_3(%rip), %rcx
movq    -16(%rbp), %rdi
movq    L_OBJC_SELECTOR_REFERENCES_(%rip), %rsi
movq    %rax, %rdx
callq   _objc_msgSend

如您所见,42存储在寄存器XMM0中。

As you can see, 42 was stored in register XMM0.

如果我们更改非正式协议,以便最后一个参数是可变参数:

And if we change the informal protocol so that the last argument is variadic:

@interface NSObject (DelegateInformalProtocol)
- (id)someMethod:(int)number hey:(id)hey ho:(id)ho, ...;
@end

然后,编译器以另一种方式准备调用站点:

then the compiler prepares the call site in another manner:

movl    $42, %edx
leaq    L__unnamed_cfstring_(%rip), %rax
leaq    L__unnamed_cfstring_3(%rip), %rcx
movq    -16(%rbp), %rdi
movq    L_OBJC_SELECTOR_REFERENCES_(%rip), %rsi
movq    %rcx, -24(%rbp)         ## 8-byte Spill
movq    %rax, %rcx
movq    -24(%rbp), %r8          ## 8-byte Reload
movb    $0, %al
callq   _objc_msgSend

请注意 movb $ 0,%al 指令。这是x86_64 ABI所要求的:调用可变参数函数时,调用者必须在AL中存储已使用的浮点寄存器的数量。在这种情况下,没有,因此 $ 0

Note the movb $0, %al instruction. That’s required by the x86_64 ABI: when calling a variadic function, the caller must store in AL the number of floating-point registers that have been used. In this case, none, hence $0.

总而言之,非正式协议除了对相关方法进行分组外,还有助于编译器确定方法的签名,并在发送消息之前正确准备调用站点。但是,鉴于Objective-C现在在正式协议声明中支持可选方法,因此不再需要非正式协议。

In summary, informal protocols, besides grouping related methods, help the compiler identify the signature of a method and correctly prepare the call site before sending a message. However, given that Objective-C now supports optional methods in a formal protocol declaration, informal protocols aren’t needed any longer.

这篇关于非正式协议有什么需要?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-14 04:33