[英]What is the purpose of declaring a protocol for a variable?
我一直在阅读有关Objective-C的协议,但我不能理解这一点:
考虑这条线
Person <CoordinateSupport> *person = [[Person alloc] init];
声明变量符合协议CoordinateSupport
的目的是什么? 这是否仅用于编译时,如果我person
分配了其他内容,或者在运行时有任何目的,Xcode会警告我吗?
我看不到变量如何符合协议。 好的,一个类很容易看到,因为您可以有一个协议来定义您希望某个类遵循但ivar可以遵循的方法。
我没看到
声明变量符合协议时的标准模式是为其赋予“任何对象”类型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
是符合Adder
的Abacus
实例”。 但是您(和编译器)已经知道Abacus
符合Adder
-它就在接口声明中! 正如rmaddy指出的那样 ,在某些情况下,您想谈论一个既是给定类,又是其子类的实例,并指定它符合协议,但是这种情况很少见,通常都指定两者不需要类和协议一致性。
有关更多信息,请查阅Apple的“使用Protcols”指南。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.