如果使用协议,则必须定义两种类类型共享的方法两次。协议通常是为特定模式保留的,例如委托模式,以增加安全性并让您更难犯错误,或者当已经嵌入类层次结构中的多个类需要共享公共方法并将这种共享记录在某种方式。如果一个类可以表示为另一个类的更专业的版本,则应该继承。
例如,假设您Vehicle
的游戏中有一个类知道如何做各种事情,例如四处走动。如果你想创建一个Car
类,你可能会继承这个Vehicle
类,这样你就可以继承它的所有方法实现;要么批发使用它们,要么实现你自己的方法版本,可能在调用超类的实现之前执行一些特定于子类的任务。子类化是为了当你想继承你的超类的特征和行为,同时以某种方式修改它。当必须将其他数据(例如实例变量)添加到类时尤其如此,因为您不能对类别执行此操作(尽管您可以使用Class Extension
,通常被视为一种私有接口)。通常,子类因此比它们的超类具有更专门的用途。
协议就是这样,协议。它们的存在是为了防止你搞砸或忘记某些东西,并确保每个对象都按照它应该做的事情,当类的行为不像他们应该做的那样时触发编译器警告。这对于委托等模式很重要,因为它是确保委托实现您需要的方法的唯一方法,而不仅仅是打破封装并知道您的委托是什么类型的对象。例如,看看下面的代码,来自我的一个项目。
//SGSprite.h
@protocol SGSpriteDelegate
- (BOOL) animation:(int)animationIndex willCompleteFrameNumber:(int)frame forSprite:(id)sender;
@end
@interface SGSprite : NSObject
@property (nonatomic, assign) id<SGSpriteDelegate> delegate;
@end
//SGViewController.h
@interface SGViewController : UIViewController <SGSpriteDelegate>
//...dreadfully boring stuff
@end
许多课程利用我的SGSprite
课程来渲染带纹理的 2D 四边形。有时,他们需要知道精灵何时到达动画的某个帧,因此SGSprite
实例需要在其委托上调用一个方法来让他们知道何时到达某些帧。确保此类实例的委托实现此方法的唯一方法是使用协议,如果有人试图分配不作为委托的对象,确实会警告我。您会注意到,如果我简单地将委托设置为普通委托,那么id
每当我在委托上调用此方法时都会收到警告,因为找不到它的实现,而如果我导入委托的标头/静态类型委托,则该类不再被很好地封装。
在大多数情况下,您在技术上不需要协议;您可以在通常遵守所述协议的所有类中定义所有没有协议的方法,并且一切都会正常工作。但是,这些常用方法不再记录在案。因此,除了知道某些类或匿名对象实现您需要它们实现的方法的安全性之外,您还可以快速判断什么做什么以及如何做。协议适用于您需要确保类或类的实例实现某些方法时,尤其是当不应该知道对象的类型以保持类被封装时。