1

在 ObjC 中,我们可以使用协议来限制id行为,因此我们可以声明类似的东西 ,直到我们提供一个值或一个非变量 as-(void)aMethod:(id<aProtocol>)aVar之前,它工作得很好,但这完全被破坏了,因为我们可以传递一个没有协议说明符的泛型变量。 .. 这正常吗?有什么解决方法吗?我错过了什么吗?idaVarid

4

3 回答 3

3

您没有理解 Objective-C 中的类型是在运行时确定的,而不是在编译时确定的。仅仅因为你说一个对象将是类型id<aProtocol>并不意味着在运行时它一定是这样的。

指定某些东西的想法id<aProtocol>是为了帮助您作为开发人员和使用您的代码的人。它可以帮助您作为开发人员,因为如果您尝试对编译器可以确定它认为在其假定类型的实例上不存在的东西调用方法(不包括转发,这可能意味着实例响应编译器无法确定的内容)。它可以帮助人们使用您的代码,因为它告诉他们在与您的代码交互时应该遵守的合同。

所以,在你的问题中,你说:

但是如果我们传递一个没有协议说明符的通用 id 变量,这将被完全破坏

好吧,编译器会警告并告诉您您正在尝试传递不符合该协议的内容,除了传递id. 这就是为什么您通常应该尝试更精确地键入内容,而不仅仅是id.

如果您有这样定义的方法:

- (void)aMethod:(id<aProtocol>)aVar

然后aVar可以是SomeSubclass这样定义的类型:

@interface SomeSubclass : NSObject <aProtocol>

然后你可以aMethod像这样使用:

SomeSubclass *obj = [SomeSubclass new];
[other aMethod:obj];
于 2012-11-16T09:09:30.457 回答
3

只需使用idless,并尽可能使用正确的类型声明变量和参数。就是说:不要乱传ids。如果您正在实现一个集合类(例如),那么id' 通常很有用。

我的方法是指定类型,并在源代码中尽可能地引入该类型。所以我省略id并添加了类型,当(例如)我从集合中获取引用时,我创建了一个变量:

MONType<MONProtocol>* thing = [array objectAtIndex:idx];
// now thing is correctly typed. use thing.

同样,如果我有一个id参数,我声明一个新变量:

- (IBAction)someAction:(id)sender
{
  NSButton * button = sender;
  // now use button, not sender

协议非常有用。很多时候,比子类化更好/更干净。

于 2012-11-16T09:16:57.117 回答
0

我(终于)发现使用 Objective-C++ 是可行的方法。假设我希望能够传递NSStringor NSNumber(而不是使用过多的泛型id,而不是使用变得无用的传递id值的协议):好吧,我可以创建一个具有两个不同构造函数的 C++ 类,一个用于每个 ObjC 类,所以传递id值不能再做(几乎直接)。例如,让我们看一下

class NSStringOrNSNumber{
    public:
        NSStringOrNSNumber(NSString *);
        NSStringOrNSNumber(NSNumber *);
};

最大的优点是带NSStringOrNSNumber参数的方法/函数可以直接获取 NSString/NSNumber 值,因为构造函数充当隐式强制转换。换句话说,如果我们有

void aFunction(NSStringOrNSNumber param);

以下调用是完全有效的:

aFunction(@"Hello!");
aFunction(@25);

唯一的(小)缺点是,如果我们想取回传递给构造函数的值,我们需要类来实现一个函数。

使用 C++ 类构造函数来获得类似的东西id<NSCoding>仍然比id<NSCoding>直接使用更好:事实上,如果我们执行以下操作

@class classOne, classTwo;

class NSCodingClass{
    private:
        NSCodingClass(classOne *);
        NSCodingClass(classTwo *);
    public:
        NSCodingClass(id<NSCoding>);
}

我们将无法将泛型id作为参数传递(因为它会模棱两可:编译器无法知道在两个私有构造函数中调用哪个构造函数)

于 2013-06-14T21:28:20.993 回答