我一直在阅读有关Objective-C的协议,但我无法理解:
考虑这一行
Person <CoordinateSupport> *person = [[Person alloc] init];
声明变量符合协议CoordinateSupport
的目的是什么?这是否仅适用于编译时间,因此如果我为person
分配不同的内容或者在运行时是否有任何用途,Xcode可以发出警告?
我无法看到变量如何符合协议。好的,一个类很容易看到,因为你可以有一个协议定义你希望某些类可以遵循的方法但是ivar?
我没有看到它。
答案 0 :(得分:1)
声明变量符合协议时的标准模式是为其赋予“任何对象”类型id
。声明变量都具有特定类型和符合协议通常是多余的 - 我将在后面解释原因。现在,我们来谈谈id<P>
类型的变量,其中P
是一些协议,以及它们为什么有用。此类型应该被理解为“符合P
的任何类的实例。”
为了具体化后面的讨论,让我们定义一个协议:
@protocol Adder
- (NSInteger)add:(NSInteger)a to:(NSInteger)b;
@end
我无法看到变量如何符合协议。
这个很容易。当变量表示实现协议中所有必需方法的类的实例时,该变量符合Objective-C协议。
@interface Abacus : NSObject <Adder>
@end
@implementation Abacus
- (NSInteger)add:(NSInteger)a to:(NSInteger)b { return a + b; }
- (NSInteger)beadCount { return 91; }
@end
鉴于此Abacus
课程,您当然可以创建新的Abacus
:
Abacus *a = [[Abacus alloc] init];
NSLog(@"%ld", (long)[a add:5 to:6]); // 11
NSLog(@"%ld", (long)[a beadCount]); // 91
但您也可以将a
声明为id<Adder
类型。请记住,这意味着a
的类型是“符合Adder
的任何类的实例。”
id<Adder> a = [[Abacus alloc] init];
NSLog(@"%ld", (long)[a add:5 to:6]); // 11
NSLog(@"%ld", (long)[a beadCount]); // Compile error: No known instance method for selector 'beadCount'
编译器抱怨,因为我们所说的关于a
类型的所有内容是它是一个符合Adder
的类,并且在Adder
协议中没有任何地方我们对名为beadCount
的方法。
声明变量符合[协议]的目的是什么?
目的是隐藏信息。当你想要一个符合Adder
的类时,你不需要关心实际的类是什么 - 你只需要id<Adder>
。想象一下,Abacus
是一个系统类,你编写了以下代码:
- (Abacus *)getAdder { return [[Abacus alloc] init]; }
- (void)doWork {
Abacus *a = [self getAdder];
// Do lots of adding...
}
然后,在iOS 42中,Apple推出了一项新的创新 - Calculator
课程!你的朋友告诉你,Calculator
将两个数字加在一起的速度是Abacus
的两倍,所有很酷的孩子都在使用它!您决定重构代码,但您意识到您不仅需要更改getAdder
的返回类型,还要更改为getAdder
返回值的所有变量的类型!瘸。如果你这样做了怎么办:
- (id<Adder>)getAdder { return [[Abacus alloc] init]; }
- (void)doWork {
id<Adder> *a = [self getAdder];
// Do lots of adding...
}
现在,当您想要迁移到Calculator
时,您只需将getAdder
的正文更改为return [[Calculator alloc] init]
即可!一条线。其余代码保持完全相同。在这种情况下,您从其余代码中隐藏从getAdder
返回的实例的真实类型。信息隐藏使重构更容易。
最后,我答应解释为什么像Abacus <Adder> *a = ...
这样的东西通常是多余的。您在这里说的是“a
是Abacus
符合Adder
的实例。”但是你(和编译器)已经知道Abacus
符合Adder
- 它就在接口声明中!作为rmaddy points out,在某些情况下,您想要讨论某个给定类或其子类的实例,并指定它符合协议,但这些情况很少见,而且最常见指定类和协议一致性是不必要的。
有关详细信息,请查看Apple的Working with Protcols指南。