繁体   English   中英

声明变量协议的目的是什么?

[英]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是符合AdderAbacus实例”。 但是您(和编译器)已经知道Abacus符合Adder -它就在接口声明中! 正如rmaddy指出的那样 ,在某些情况下,您想谈论一个既是给定类,又是其子类的实例,并指定它符合协议,但是这种情况很少见,通常都指定两者不需要类和协议一致性。

有关更多信息,请查阅Apple的“使用Protcols”指南。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM