天天看點

oc——類——協定

概述

協定,protocol,是一種特殊的interface,這種特殊的interface不允許定義資料成員,允許聲明Method,protocol純粹作為接口使用,是以沒有對應implementation

  • protocol不允許定義資料成員
  • protocol允許聲明Method,包括instance method(-)和class method(+),protocol沒有對應implementation
  • protocol可繼承protocol,而且支援多繼承,protocol繼承本質是union父protocol的Method聲明到子protocol中
  • protocol純粹作為接口使用,是以沒有實體,不能執行個體化
  • protocol的Method聲明允許的修飾詞包括@required和@optional,預設@required,@required是必須實作接口,@optional是可選實作接口
  • @required和@optional的唯一差別是對應接口沒有實作時編譯是否warning(@required編譯warning,@optional編譯不warning)

protocol

@interface FBFood : NSObject

@end

@implementation FBFood

@end

@protocol FBFeedFood1

- (void)feedRice:(int)rice andMeat:(int)meat;
- (void)feedFruit:(int)fruit andFish:(int)fish;

@end

@protocol FBFeedFood2

- (void)feedRice:(int)rice andMeat:(FBFood *)meat;
- (void)feedFruit:(int)fruit andFish:(FBFood *)fish;

@end

@protocol FBFeedFood <FBFeedFood1, FBFeedFood2>

- (void)feedFruit:(FBFood *)fruit andFish:(FBFood *)fish;

@optional
- (void)feed;

@end

@interface FBAnimal : NSObject <FBFeedFood>

@end

@implementation FBAnimal

- (void)feedRice:(int)rice andMeat:(int)meat
{
    NSLog(@"feedRice:andMeat:");
}

- (void)feedFruit:(FBFood *)fruit andFish:(FBFood *)fish
{
    NSLog(@"feedFruit:andFish:");
}

@end
           

總結:

  • protocol可繼承protocol,而且支援多繼承,protocol繼承本質是union父protocol的Method聲明到子protocol中,是以不可避免的會與已有Method聲明相同(SEL相同),重複的Method聲明的參數清單可能會不同,union時選取重複Method聲明的優先級為:FBFeedFood->FBFeedFood1->FBFeedFood2(即@protocol FBFeedFood <FBFeedFood1, FBFeedFood2>的protocol定義順序)

應用

@protocol FBFeedFood1

- (void)feedRice:(int)rice andMeat:(int)meat;

@end

@protocol FBFeedFood2

- (void)feedFruit:(int)fruit andFish:(int)fish;

@end

@protocol FBFeedFood <FBFeedFood1, FBFeedFood2>

@end

@protocol FBGuard

@required
- (void)watch;

@optional
- (void)attack;

@end

@interface FBAnimal : NSObject <FBFeedFood>
{
@public
    int _food;
}

@end

@implementation FBAnimal

- (void)feedRice:(int)rice andMeat:(int)meat
{
    NSLog(@"feedRice:andMeat:");
}

- (void)feedFruit:(int)fruit andFish:(int)fish
{
    NSLog(@"feedFruit:andFish:");
}

@end

@interface FBDog : FBAnimal <FBGuard>
{
@public
    int _vol;
}

- (void)bark;

@end

@implementation FBDog

- (void)bark
{
    NSLog(@"bark");
}

- (void)watch
{
    NSLog(@"watch");
}

@end
           
- (void)use_protocol
{
    NSObject<FBFeedFood> *animal1 = [[FBAnimal alloc] init];
    //animal1->_food = 5;
    [animal1 feedRice:5 andMeat:8];
    [animal1 methodForSelector:@selector(feedFruit:andFish:)];
    //[animal1 unknownMethod];
    
    id<FBFeedFood> animal2 = [[FBAnimal alloc] init];
    //animal2->_food = 5;
    [animal2 feedFruit:5 andFish:8];
    //[animal2 methodForSelector:@selector(feedFruit:andFish:)];
    //[animal2 unknownMethod];
    
    id<FBGuard> animal3 = [[FBDog alloc] init];
    //animal3->_vol = 8;
    //[animal3 feedRice:5 andMeat:8];
    //[animal3 methodForSelector:@selector(feedFruit:andFish:)];
    [animal3 watch];
    
    FBAnimal<FBFeedFood> *animal4 = [[FBAnimal alloc] init];
    animal4->_food = 5;
    [animal4 feedRice:5 andMeat:8];
    [animal4 feedFruit:5 andFish:8];
    
    FBDog<FBGuard> *animal5 = [[FBDog alloc] init];
    //animal4->_vol = 8;
    [animal5 bark];
    [animal5 watch];
    
    NSLog(@"FBAnimal confirm FBFeedFood1 = %d", [FBAnimal conformsToProtocol:@protocol(FBFeedFood1)]);
    NSLog(@"FBAnimal confirm FBFeedFood = %d", [FBAnimal conformsToProtocol:@protocol(FBFeedFood)]);
    NSLog(@"FBAnimal confirm FBGuard = %d", [FBAnimal conformsToProtocol:@protocol(FBGuard)]);
    
    NSLog(@"FBDog confirm FBFeedFood1 = %d", [FBDog conformsToProtocol:@protocol(FBFeedFood1)]);
    NSLog(@"FBDog confirm FBFeedFood = %d", [FBDog conformsToProtocol:@protocol(FBFeedFood)]);
    NSLog(@"FBDog confirm FBGuard = %d", [FBDog conformsToProtocol:@protocol(FBGuard)]);
}
           

output:

feedRice:andMeat:
feedFruit:andFish:
watch
feedRice:andMeat:
feedFruit:andFish:
bark
watch
FBAnimal confirm FBFeedFood1 = 1
FBAnimal confirm FBFeedFood = 1
FBAnimal confirm FBGuard = 0
FBDog confirm FBFeedFood1 = 1
FBDog confirm FBFeedFood = 1
FBDog confirm FBGuard = 1
           

使用protocol兩種方式:

  • 類<protocol1, protocol2...> *對象名
  • id<protocol1, protocol2...> 對象名

總結:

  • 類<protocol1, protocol2...> *允許通路類+協定的成員,id<protocol1, protocol2...>隻允許通路協定的成員,否則編譯warning
  • 習慣使用id<protocol1, protocol2...>定義執行個體對象,簡潔明了,因為使用protocol一般隻關注protocol的Method接口(不大使用類提供的功能)
  • 類遵守協定并不確定類實作了協定的所有Method(@required不實作,編譯warning,@optional不實作,編譯不warning)
  • 父類遵守的protocol,子類繼承遵守