在 Objective-C 中定义协议的类别?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1521267/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Defining categories for protocols in Objective-C?
提问by Jochen
In Objective-C, I can add methods to existing classes with a category, e.g.
在 Objective-C 中,我可以将方法添加到具有类别的现有类中,例如
@interface NSString (MyCategory)
- (BOOL) startsWith: (NSString*) prefix;
@end
Is it also possible to do this with protocols, i.e. if there was a NSString protocol, something like:
是否也可以使用协议来做到这一点,即如果有一个 NSString 协议,比如:
@interface <NSString> (MyCategory)
- (BOOL) startsWith: (NSString*) prefix;
@end
I want to do this since I have several extensions to NSObject (the class), using only public NSObject methods, and I want those extensions also to work with objects implementing the protocol .
我想这样做是因为我对 NSObject(类)有几个扩展,仅使用公共 NSObject 方法,并且我希望这些扩展也可以与实现协议的对象一起使用。
To give a further example, what if I want to write a method logDescription that prints an object's description to the log:
再举一个例子,如果我想编写一个方法 logDescription 将对象的描述打印到日志中,该怎么办:
- (void) logDescription {
NSLog(@"%@", [self description]);
}
I can of course add this method to NSObject, but there are other classes that do not inherit from NSObject, where I'd also like to have this method, e.g. NSProxy. Since the method only uses public members of protocol , it would be best to add it to the protocol.
我当然可以将此方法添加到 NSObject,但还有其他类不从 NSObject 继承,我也希望在其中使用此方法,例如 NSProxy。由于该方法仅使用 protocol 的公共成员,因此最好将其添加到协议中。
Edit: Java 8 now has this with "virtual extension methods" in interfaces: http://cr.openjdk.java.net/~briangoetz/lambda/Defender%20Methods%20v4.pdf. This is exactly what I would like to do in Objective-C. I did not see this question earning this much attention...
编辑:Java 8 现在在接口中具有“虚拟扩展方法”:http: //cr.openjdk.java.net/~briangoetz/lambda/Defender%20Methods%20v4.pdf。这正是我想在 Objective-C 中做的事情。我没有看到这个问题引起了如此多的关注......
Regards, Jochen
问候, 乔亨
采纳答案by Alex Gray
extObjC has the NEATEST stuffyou can do with Protocols / Categories... first off is @concreteprotocol...
extObjC 有你可以用协议/类别做的最简单的东西......首先是@concreteprotocol......
- Defines a "concrete protocol," which can provide default implementations of methods within protocol.
- An
@protocolblock should exist in a header file, and a corresponding@concreteprotocolblock in an implementation file. - Any object that declares itself to conform to this protocol will receive its method implementations, but only if no method by the same name already exists.
- 定义一个“具体协议”,它可以提供协议内方法的默认实现。
- 一个
@protocol块应该存在于一个头文件中,一个对应的块应该存在@concreteprotocol于一个实现文件中。 - 任何声明自己符合此协议的对象都将接收其方法实现,但前提是不存在同名的方法。
MyProtocol.h
MyProtocol.h
@protocol MyProtocol
@required - (void)someRequiredMethod;
@optional - (void)someOptionalMethod;
@concrete - (BOOL)isConcrete;
MyProtocol.m
MyProtocol.m
@concreteprotocol(MyProtocol) - (BOOL)isConcrete { return YES; } ...
so declaring an object MyDumbObject : NSObject <MyProtocol>will automatically return YESto isConcrete.
所以声明一个对象MyDumbObject : NSObject <MyProtocol>会自动返回YES到isConcrete.
Also, they have pcategoryinterface(PROTOCOL,CATEGORY)which "defines the interface for a category named CATEGORY on a protocol PROTOCOL". Protocol categories contain methods that are automatically applied to any class that declares itself to conform to PROTOCOL." There is an accompanying macro you also have to use in your implementation file. See the docs.
此外,它们具有pcategoryinterface(PROTOCOL,CATEGORY)“为协议 PROTOCOL 上名为 CATEGORY 的类别定义接口”。协议类别包含自动应用于任何声明自己符合协议的类的方法。”您还必须在实现文件中使用一个随附的宏。请参阅文档。
Last, but NOT least / not directlyrelated to @protocolsis
synthesizeAssociation(CLASS, PROPERTY), which "synthesizes a property for a class using associated objects. This is primarily useful for adding properties to a class within a category. PROPERTY must have been declared with @propertyin the interface of the specified class (or a category upon it), and must be of object type."
最后,但并非最不重要/与is
不直接相关,它“使用关联对象为类合成属性。这主要用于向类别中的类添加属性。必须在指定的接口中声明属性类(或其上的类别),并且必须是对象类型。”@protocolssynthesizeAssociation(CLASS, PROPERTY)@property
So manyof the tools in this library open (way-up) the things you can do with ObjC... from multiple inheritance... to well, your imagination is the limit.
这个库中的许多工具打开(向上)你可以用 ObjC 做的事情......从多重继承......到好吧,你的想象力是极限。
回答by Dave DeLong
Short answer: No.
简短的回答:没有。
Long answer: how would this work? Imagine you couldadd methods to existing protocols? How would this work? Imagine we wanted to add another method to NSCoding, say -(NSArray *) codingKeys;This method is a required method that returns an array of the keys used to encoding the object.
长答案:这将如何工作?想象一下,您可以向现有协议添加方法吗?这将如何运作?想象一下,我们想向 NSCoding 添加另一个方法,比如说-(NSArray *) codingKeys;这个方法是一个必需的方法,它返回一个用于编码对象的键数组。
The problem is that there are existing classes (like, say NSString) that already implement NSCoding, but don't implement our codingKeysmethod. What should happen? How would the pre-compiled framework know what to do when this requiredmessage gets sent to a class that does not implement it?
问题是已有类(比如 NSString)已经实现了 NSCoding,但没有实现我们的codingKeys方法。应该发生什么?当这个必需的消息被发送到一个没有实现它的类时,预编译的框架如何知道该怎么做?
You could say "we can add the definition of this method via a category" or "we could say that any methods added via these protocol categories are explicitly optional". Yes, you could do this and theoretically get around the problem I've described above. But if you're going to do that, you might as well just make it a category in the first place, and then check to make sure the class respondsToSelector:before invoking the method.
您可以说“我们可以通过类别添加此方法的定义”或“我们可以说通过这些协议类别添加的任何方法都是明确可选的”。是的,你可以这样做,理论上可以解决我上面描述的问题。但是,如果您打算这样做,您不妨首先将其设为一个类别,然后respondsToSelector:在调用该方法之前检查以确保该类。
回答by Douglas Mayle
While it's true that you can't define categories for protocols (and wouldn't want to, because you don't know anything about the existing object), you can define categories in such a way that the code only applies to an object of the given type that has the desired protocol (sort of like C++'s partial template specialization).
虽然您确实无法为协议定义类别(并且不想定义,因为您对现有对象一无所知),但您可以通过代码仅适用于以下对象的方式来定义类别具有所需协议的给定类型(有点像 C++ 的部分模板特化)。
The main use for something like this is when you wish to define a category that depends on a customized version of a class. (Imagine that I have UIViewController subclasses that conform to the Foo protocol, meaning they have the foo property, my category code may have need of the foo property, but I can't apply it to the Foo protocol, and if I simply apply it to UIViewController, the code won't compile by default, and forcing it to compile means someone doing introspection, or just screwing up, might call your code which depends on the protocol. A hybrid approach could work like this:
此类的主要用途是当您希望定义依赖于类的自定义版本的类别时。(假设我有符合 Foo 协议的 UIViewController 子类,这意味着它们具有 foo 属性,我的类别代码可能需要 foo 属性,但我无法将其应用于 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
With the hybrid approach, you can write the code only once (per class that is supposed to implement the protocol) and be sure that it won't affect instances of the class that don't conform to the protocol.
使用混合方法,您只能编写一次代码(每个应该实现协议的类),并确保它不会影响不符合协议的类的实例。
The downside is that property synthesis/definition still has to happen in the individual subclasses.
缺点是属性合成/定义仍然必须在各个子类中进行。
回答by Chuck
It isn't really meaningful to do so since a protocol can't actually implement the method. A protocol is a way of declaring that you support some methods. Adding a method to this list outside the protocol means that all "conforming" classes accidentally declare the new method even though they don't implement it. If some class implemented the NSObject protocol but did not descend from NSObject, and then you added a method to the protocol, that would break the class's conformance.
这样做并没有什么意义,因为协议实际上无法实现该方法。协议是一种声明您支持某些方法的方式。在协议之外向这个列表添加一个方法意味着所有“符合”的类都会意外地声明新方法,即使它们没有实现它。如果某个类实现了 NSObject 协议但不是从 NSObject 继承而来,然后您向该协议添加了一个方法,那将破坏该类的一致性。
You can, however, create a new protocol that includes the old one with a declaration like @protocol SpecialObject <NSObject>.
但是,您可以创建一个新协议,其中包含带有类似声明的旧协议@protocol SpecialObject <NSObject>。
回答by slf
I think you may be mixing up terms here and there. Extensions, Categories, Protocols, Interfaces and Classes are all different things in Objective-C. In The Objective-C 2.0 LanguageApple describes the differences very well, including the benefits and drawbacks to using categories and extensions.
我认为您可能在这里和那里混淆了术语。扩展、类别、协议、接口和类在 Objective-C 中都是不同的东西。在Objective-C 2.0 语言中,Apple 很好地描述了这些差异,包括使用类别和扩展的优点和缺点。
If you think about it, what is a "Category" or "Extension" in the conceptual sense? It's a way of adding functionality to a Class. In Objective-C, protocols are designed to have no implementation. Therefore, how would you add or extend the implementation of something that doesn't have implementation to begin with?
如果您考虑一下,概念意义上的“类别”或“扩展”是什么?这是向类添加功能的一种方式。在 Objective-C 中,协议被设计为没有实现。因此,您将如何添加或扩展没有实现的东西的实现?
回答by pxl
if you're already writing a category, why not just add in the protocol definition in the header right after the category definition?
如果您已经在编写一个类别,为什么不直接在类别定义之后的标题中添加协议定义呢?
i.e.
IE
@interface NSString (MyCategory)
- (BOOL) startsWith: (NSString*) prefix;
@end
@protocol MyExtendedProtocolName <NSString>
//Method declarations go here
@end
this way any class that imports the category header will also get the protocol definition, and you can add it into your class..
这样,任何导入类别标头的类也将获得协议定义,您可以将其添加到您的类中..
@interface MyClass <OriginalProtocol,MyExtendedProtocolName>
also, be careful when subclassing NSString, it's a cluster and you may not always get the behaviour you're expecting.
另外,在继承 NSString 时要小心,它是一个集群,您可能并不总是得到您期望的行为。
回答by Senseful
Adam Sharp posted a solutionthat worked for me.
It involves 3 steps:
它包括3个步骤:
- Defining the methods you want to add as
@optionalon a protocol. - Making the objects you want to extend conform to that protocol.
- Copying those methods into those objects at runtime.
- 定义要
@optional在协议上添加的方法。 - 使您要扩展的对象符合该协议。
- 在运行时将这些方法复制到这些对象中。
Check out the link for the full details.
查看链接以获取完整的详细信息。

