【发布时间】:2010-01-05 23:59:05
【问题描述】:
我想知道是否有人可以解释什么是 Objective C 中的非正式协议?我试图在苹果文档和其他一些书籍上理解它,但我的头脑仍然在旋转,所以如果有人能举例说明,我将非常感激。
谢谢。
【问题讨论】:
标签: objective-c
我想知道是否有人可以解释什么是 Objective C 中的非正式协议?我试图在苹果文档和其他一些书籍上理解它,但我的头脑仍然在旋转,所以如果有人能举例说明,我将非常感激。
谢谢。
【问题讨论】:
标签: objective-c
非正式协议,正如 Jonnathan 所说,通常是在 NSObject 上声明的一个类别,没有相应的实现(大多数情况下——很少有一个在 NSObject 上提供虚拟实现)。
从 10.6(以及在 iPhone SDK 中)开始,不再使用此模式。具体来说,在 10.5(及之前)中声明如下:
@interface NSObject(NSApplicationNotifications)
- (void)applicationWillFinishLaunching:(NSNotification *)notification;
...
@interface NSObject(NSApplicationDelegate)
- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender;
...
现在声明为:
@protocol NSApplicationDelegate <NSObject>
@optional
- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender;
...
- (void)applicationWillFinishLaunching:(NSNotification *)notification;
...
也就是说,非正式协议现在被声明为 @protocols 和一堆 @optional 方法。
在任何情况下,非正式协议都是方法声明的集合,您可以选择实现这些方法来改变行为。通常,但不总是,方法实现是在委托的上下文中提供的(例如,表格视图的数据源必须实现少数必需的方法,并且可以选择实现一些额外的方法)。
【讨论】:
非正式协议的一个常见示例是定义回调。假设您正在使用一个允许您在后台下载某些内容的库。该库允许您注册一个回调对象,以便在完成时调用。
- (void)download:(NSURL*)url whenComplete:(id)callback
下载完成后,它会在你的回调对象上调用一个特定的方法:
- (void)downloadComplete:(NSURL*)url
当然,不能保证你的回调对象确实实现了这个方法。非正式协议使用类别在NSObject 上提供这些方法的简单实现。结果,系统中的所有对象都会响应downloadComplete: 方法,尽管默认情况下它们不会响应该方法。覆盖downloadComplete: 方法的类可以提供更多有用的功能。
到目前为止,您可以使用正式的协议来完成同样的事情。但是,非正式协议允许您使用可选方法。实现正式协议的类必须为协议中的每个方法提供实现。实现非正式协议的类可以省略任何方法的实现 - 它已经从 NSObject 继承了实现。
从 Objective-C 2.0 开始,正式协议可以包含可选方法。此外,Apple 可能会放弃新 API 的非正式协议 - UIAccelerometerDelegate 是正式协议。
【讨论】:
callback 一词的使用在这里可能会造成混淆,尤其是在存在块的世界中。你说的是委托。 (我意识到这个答案在 2010 年可能更有意义。)
非正式协议是一种向对象添加可选方法的方式通过类别。
所以可能会产生一个疑问
如果协议本身有任何可选方法,它会成为非正式协议吗?
答案是否定的。
如果方法在协议中声明并且据说符合一个类没有任何类别的使用那么它是正式协议。
注意:
objective c 2.0 中引入了协议中的可选方法,因此在此之前通过非正式协议即通过类别来实现目的。
类别:
这是一种语言级别的功能,旨在替代子类化(即继承)。
我希望它能对此有所启发..
【讨论】:
"Note :" 给了我完整的图片:-)
我们通过对类别声明中的方法进行分组来定义informal protocol,
@interface NSObject ( MyXMLSupport )
- initFromXMLRepresentation:(NSXMLElement *)XMLElement;
- (NSXMLElement *)XMLRepresentation;
@end
Informal protocols 通常被声明为NSObject 类的类别,因为这广泛地关联
任何继承自 NSObject 的类的方法名称。
因为所有类都继承自根类,
这些方法不限于继承层次结构的任何部分。 (也可以声明
informal protocol 作为另一个类的一个类别,以将其限制为继承层次结构的某个分支,
但没有什么理由这样做)。
当用于声明协议时,类别接口没有对应的实现。反而, 实现协议的类在自己的接口文件中再次声明方法并定义它们 以及它们的实现文件中的其他方法。
【讨论】:
所有的非正式协议都是某个类(通常是NSObject)的一个类别,它声明了协议的接口。 AppKit 经常使用它来进行委托。
您编写的子类可以实现这些方法。这与正式协议之间的区别在于,正式协议是使用@protocol ... @end 表示法声明的。没有检查类是否实现给定的非正式协议。
我几乎总是使用正式协议,但我认为如果您想提供默认行为(只需为您的类别提供可被覆盖的实现),非正式协议会很有用。
【讨论】:
基于“Jonathan Sterling”的回答,我可以说以下代码代表非正式协议吗?
苹果文档:
“当用于声明协议时,类别接口没有对应的实现。而是实现该协议的类在自己的接口文件中再次声明方法,并在其实现文件中与其他方法一起定义它们。 "
#import <Foundation/Foundation.h>
@interface Cat1 : NSObject {
}
- (void) simpleMethod;
@end
@implementation Cat1
- (void) simpleMethod
{
NSLog(@"Simple Method");
}
@end
@interface Cat1 (Cat2)
- (void) addingMoreMethods;
@end
@interface MYClass : Cat1
@end
@implementation MYClass
- (void) addingMoreMethods
{
NSLog(@"Testing!");
}
@end
int main (int argc, const char * argv[]) {
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
MYClass *myclass = [[MYClass alloc] init];
[myclass addingMoreMethods];
[myclass release];
[pool drain];
return 0;
}
【讨论】:
if([myclass respondsToSelector: @selector(addingMoreMethods)]) [myclass addingMoreMethods];。
一个非正式的协议定义了一个对象必须理解的方法。这被称为“符合协议”。遵守协议独立于类层次结构。 当声明一个指针来保存对一个对象的引用时,你可以定义这个对象应该遵守哪些协议。如果您编写的代码分配的对象不符合所有必需的协议,您将在编译时收到警告。 非正式协议可帮助您依赖对象可以理解的一组方法。您不必在代码中调用 isKindOfClass: 或 respondsTo: 来检查传入的对象是否适合您的处理。 协议是一种面向方面的编程。
【讨论】: