开发者

What's the need of Informal Protocols?

开发者 https://www.devze.com 2023-04-08 19:16 出处:网络
I\'ve read the online docs about formal and informal pr开发者_Python百科otocols on Apple\'s documentation site, but I missed the point about informal protocols. I mean,

I've read the online docs about formal and informal pr开发者_Python百科otocols on Apple's documentation site, but I missed the point about informal protocols. I mean,

  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.

EDIT: 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.

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"];
}

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.

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 you can see, 42 was stored in register EDX.

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

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

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.

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.

0

精彩评论

暂无评论...
验证码 换一张
取 消