11

鉴于此协议定义:

@protocol MyProtocol <NSObject>
@property (nonatomic, strong) NSString *someProperty;
@end

为什么 Xcode 会很乐意为这个语句提供自动完成功能:

id<MyProtocol> thing = [ThingManager currentThing];
[thing someProperty]; // Xcode offered autocompletion here

但是当我尝试使用点符号访问相同的属性时,它不提供自动完成功能:

id<MyProtocol> thing = [ThingManager currentThing];
thing.someProperty; // Xcode claimed there were 
                    // "No completions" available
                    // after the period
4

2 回答 2

6

因为id是基本类型,Xcode 和 CLANG 对提供点语法访问感到不安,因为点语法只是对普通对象中关联的 setter 或 getter 的方法调用的语法糖,但 id 没有定义的方法成员。从 C 方面来看,id 是编译器无法看到其成员的结构指针的 typedef,这意味着它无法访问它们(更不用说在点访问之前需要取消引用 id 的事实)做出任何语义意义)。

回到 Objective-C 方面,协议实际上并没有向声称实现它们的类添加方法或属性,而是作为其他类的说明符,即符合给定协议的对象实现了一系列方法。至于正在完成的方法语法,Xcode 将所有文件的所有给定方法汇集到一个给定的 .m 文件中,因为类型 id 的对象可以接收任何消息*

*当然,它可以接收消息,但是如果它没有实现它仍然会崩溃。

于 2013-01-26T06:08:03.170 回答
2

这是一个切题的答案,也是一个思想实验。

但在此之前,我会注意到您可以通过 skipping 获得您的属性自动完成id,如下所示:

NSObject<MyProtocol> *thing;
thing.▮

但是假设您不希望整个NSObject方法列表影响您的完成,您可以执行类似的操作

EmptyClass<MyProtocol> *thing = [ThingManager currentThing];

// completion list will be (close) to only the protocol props
thing.▮

EmptyClass提供类似的“好的,没有承诺!” 作用id,但自动完成喜欢它。这是EmptyClass

NS_ROOT_CLASS
@interface EmptyClass

@end

@implementation EmptyClass

+ (void)initialize {} // required

@end

请注意,其中的对象thing实际上并不植根于EmptyClass不可能),所以这是高度伪造的。然而,它

  • 大大低估thing实际可以做什么。
  • 不(不能!)实例化一个EmptyClass对象。

那为什么不呢?如果你真的很努力,你可能会导致类似的问题

EmptyClass *nooooo = [[NSClassFromString(@"EmptyClass") alloc] init];

这将立即异常。但并不是真正需要避免的棘手错误。

一个陷阱不会让我感到惊讶,但我现在不知道。请留下评论,如果你这样做。

于 2014-05-02T17:49:46.387 回答