1

我一直在阅读有关 Objective-C 协议的内容,但我无法理解这一点:

考虑这条线

Person <CoordinateSupport> *person = [[Person alloc] init];

声明变量符合协议的目的是什么CoordinateSupport?这只是为了编译时间,所以如果我分配了不同的东西person或者在运行时有什么目的,Xcode 可以警告我?

我看不到变量如何符合协议。好的,一个类很容易看到,因为您可以有一个协议定义您希望某个类遵循的方法,但一个 ivar?

我没有看到它。

4

1 回答 1

1

声明变量符合协议时的标准模式是给它“任何对象”类型,id. 声明一个变量既具有特定类型符合协议通常是多余的——我稍后会解释原因。现在,让我们谈谈 type 的变量,一些协议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只是 type id<Adder。请记住,这意味着 of 的类型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,只需更改 to 的主体getAdder即可return [[Calculator alloc] init]!一条线。您的其余代码保持完全相同。在这种情况下,您隐藏getAdder了从其余代码返回的实例的真实类型。信息隐藏使重构更容易。

最后,我答应解释为什么类似的东西Abacus <Adder> *a = ...通常是多余的。你在这里说的是“是符合a的实例。” 但是您(和编译器)已经知道符合- 它就在接口声明中!正如rmaddy 指出的那样,在某些情况下,您想要谈论一个实例,它要么是给定的类,要么是其子类,并且还要指定它符合协议,但这种情况很少见,并且通常同时指定两者不需要类和协议一致性。AbacusAdderAbacusAdder

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

于 2017-04-07T18:25:48.707 回答