在 Objective-C 中,我可以使用类别向现有类添加方法,例如

@interface NSString (MyCategory)
- (BOOL) startsWith: (NSString*) prefix;
@end

是否也可以通过协议来做到这一点,即如果有 NSString 协议,类似于:

@interface <NSString> (MyCategory)
- (BOOL) startsWith: (NSString*) prefix;
@end

我想这样做,因为我有几个 NSObject (类)扩展,仅使用公共 NSObject 方法,并且我希望这些扩展也可以与实现协议的对象一起使用。

举一个进一步的例子,如果我想编写一个方法 logDescription 将对象的描述打印到日志中该怎么办:

- (void) logDescription {
    NSLog(@"%@", [self description]);
}

我当然可以将此方法添加到 NSObject,但是还有其他类不继承自 NSObject,我也希望拥有此方法,例如NSProxy。由于该方法仅使用协议的公共成员,因此最好将其添加到协议中。

编辑:Java 8 现在在接口中具有“虚拟扩展方法”: http://cr.openjdk.java.net/~briangoetz/lambda/Defender%20Methods%20v4.pdf. 。这正是我想要在 Objective-C 中做的事情。我没有看到这个问题引起如此多的关注......

问候,约翰

有帮助吗?

解决方案

extObjC 有最棒的东西 您可以使用协议/类别...首先是 @concreteprotocol...

  • 定义一个“具体协议”,它可以提供协议内方法的默认实现。
  • 一个 @protocol 块应该存在于头文件中,并且有相应的 @concreteprotocol 块在实现文件中。
  • 任何声明自己符合此协议的对象都将接收其方法实现,但前提是不存在同名的方法。

我的协议.h

@protocol MyProtocol 
@required - (void)someRequiredMethod;
@optional - (void)someOptionalMethod;
@concrete - (BOOL)isConcrete;   

我的协议.m

 @concreteprotocol(MyProtocol) - (BOOL)isConcrete { return YES; } ...

所以声明一个对象 MyDumbObject : NSObject <MyProtocol> 会自动返回 YESisConcrete.

另外,他们还有 pcategoryinterface(PROTOCOL,CATEGORY) 它“定义协议 PROTOCOL 上名为 CATEGORY 的类别的接口”。协议类别包含自动应用于任何声明自身符合协议的类的方法。”您还必须在实现文件中使用一个随附的宏。请参阅文档。

最后但并非最不重要的/不是 直接地 相关 @protocolssynthesizeAssociation(CLASS, PROPERTY), ,它“使用关联对象合成类的属性。这主要用于向类别内的类添加属性。财产必须已申报 @property 在指定类(或其上的类别)的接口中,并且必须是对象类型。”

很多 这个库中的工具开放(向上)您可以使用 ObjC 做的事情...来自多重继承...好吧,你的想象力是有限的。

其他提示

短的答案:无

龙答:如何将这项工作?想象一下,你的可能的方法添加到现有的协议?如何将这项工作?假设我们希望增加另一种方法来NSCoding,说-(NSArray *) codingKeys;此方法返回用于编码对象的键的阵列的需要的方法。

但问题是,有现有类(比如,说的NSString)已经实现NSCoding,但没有实现我们的codingKeys方法。应该发生什么?如何将预编译的框架,知道什么时候该的需要的消息被发送到一个类,没有实现它做什么?

您可以说“我们可以通过类别添加此方法的定义”或“我们可以说,通过这些协议类别添加任何方法都明确地可选的”。是的,你可以做到这一点,并从理论上得到解决我上面提到的问题。但是,如果你要做到这一点,你可能也只是使它在首位的类别,然后检查调用方法之前,以确保该类respondsToSelector:

虽然这是事实,你不能对协议定义类别(不会想,因为你不知道现有对象的任何东西),你可以定义这样的代码只适用于类具有所需的协议给定类型的对象(有点像C ++的模板偏特)。

这样的事情的主要用途是,当你希望定义取决于类的定制版本的类别。 (想象一下,我有一个符合美孚的协议,这意味着他们有富物业的UIViewController子类,我的类别代码可能需要foo的财产,但我不能把它应用到了富协议,如果我简单地应用它到的UIViewController,代码将不会默认编译,并迫使它来编译意味着有人在做反省,或者只是搞砸了,可能会打电话给你的代码,这取决于协议的混合方法可以像这样工作:

@protocol Foo
- (void)fooMethod

@property (retain) NSString *foo;
@end

@implementation UIViewController (FooCategory)

- (void)fooMethod {
    if (![self conformsToProtocol:@protocol(Foo)]) {
        return;
    }

    UIViewController<Foo> *me = (UIViewController<Foo>*) self;
    // For the rest of the method, use "me" instead of "self"
    NSLog(@"My foo property is \"%@\"", me.foo);
}
@end

通过混合方法,您可以编写代码只有一次(每一个应该实现协议类),并确保它不会影响那些不符合协议的类的实例。

的缺点是,属性合成/定义仍然有在不同的子类的情况发生。

有没有太大意义,因为一个协议不能实际实现该方法这样做。协议是宣布您支持某些方法的一种方式。添加一个方法到外面协议这份名单意味着,所有“符合”类意外宣布新的方法,即使他们没有实现它。如果某些类实现NSObject的协议,但并没有从NSObject的下降,然后添加一个方法的协议,这将打破类的一致性。

可以,然而,创建一个新的协议,该协议包括旧的与像@protocol SpecialObject <NSObject>声明。

我认为您可能在这里或那里混淆了术语。扩展、类别、协议、接口和类在 Objective-C 中都是不同的东西。在 Objective-C 2.0 语言 苹果很好地描述了这些差异,包括使用类别和扩展的优点和缺点。

如果你想一想,概念意义上的“类别”或“扩展”是什么?这是向类添加功能的一种方法。在 Objective-C 中,协议被设计为没有实现。因此,您将如何添加或扩展那些本来就没有实现的东西的实现呢?

如果你已经写一个类,为什么不只是添加在协议定义标头中的类定义后吧?

@interface NSString (MyCategory)
- (BOOL) startsWith: (NSString*) prefix;
@end

@protocol MyExtendedProtocolName <NSString>
//Method declarations go here
@end

这方式进口的类别标题也将获得协议定义的任何类,你可以把它添加到您的类..

@interface MyClass <OriginalProtocol,MyExtendedProtocolName>

也,子类的NSString时要小心,这是一个簇,你可能不会总是得到你期望的行为。

亚当·夏普 发布了一个解决方案 这对我有用。

它涉及 3 个步骤:

  1. 定义您要添加的方法 @optional 在一个协议上。
  2. 使您想要扩展的对象符合该协议。
  3. 在运行时将这些方法复制到这些对象中。

查看链接了解完整详细信息。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top