Object C學習筆記15-協議(protocol)

賀臣發表於2014-03-21

  在.NET中有介面的概念,介面主要用於定義規範,定義一個介面關鍵字使用interface。而在Object C 中@interface是用於定義一個類的,這個和.NET中有點差別。在Object C中有一個協議(protocol) 的概念,這個和.NET中的interface類似。

  協議(Protocol) 在列出的方法在本類中並沒有相應實現,而是別的類來實現這些方法,而定義協議必須使用protocol關鍵字。

 

  一. 如何定義protocol的定義

    如何使用XCode新建一個協議.h 檔案

 

 

 

 

 

 

 

 

定義協議程式碼如下:

#import <Foundation/Foundation.h>

@protocol ProtocolCom <NSObject>

@required
-(void) eat;

@optional
-(void) write;

@end
定義協議程式碼

    從以上程式碼可以看到,我們可以瞭解到定義一個協議基本如下結構:

    @protocol protocolName<NSObject>

    @required

    //方法宣告

    @optional

    //方法宣告

    .......

    @end

從剛才的程式碼中,定義了一個名為ProtocolCom的協議,其中有兩個方法 eat ,write;  上面也提到過了,protocol相當於.net中的interface 介面,介面就是用於定義規則的,但是Object C中的協議和.NET中的interface還是有點區別的,這裡就涉及到@required,@optional 。 這兩個標註在方法上面是有特殊含義的,這個後面詳細說明。

#import <Foundation/Foundation.h>

@protocol ProtocolCom 

@required
-(void) eat;

@optional
-(void) write;

@end
修改協議程式碼

    從上面修改的程式碼對比來看,在協議定義後面缺少了<NSObject> ,這段程式碼仍然能夠正常執行,其實<NSObject>也本身可以理解為ProtocolCom要遵循NSObject 協議,這個和.NET中一個類如果沒有顯示指定繼承哪個類,那麼預設就是繼承的Object類的道理是一樣的,所以這裡可以省略。

    這裡我在定義一個協議MyProtocol,這個協議必須遵循協議ProtocolCom協議。剛才上面已經瞭解到了協議後面跟<NSObject>,道理一樣如果MyProtocol要遵循協議ProtocolCom就是用此種方式來實現,具體程式碼如下:

#import <Foundation/Foundation.h>
#import "ProtocolCom.h"

@protocol MyProtocol <ProtocolCom>

@required
-(void) setname;

@optional
-(void) setage;

@end
協議的"繼承"

    在Object C 協議中並不習慣說繼承,而是是用遵從或者遵循,比如A協議遵循B協議。這裡專業上得術語可能不太準確,姑且這麼說,先理解意思。

    然後我們是用一個新的類來實現協議MyProtocol中的所有方法。

#import <Foundation/Foundation.h>
#import "MyProtocol.h"

@interface Student : NSObject<MyProtocol>

@end



-------------------------------------------
#import "Student.h"

@implementation Student

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

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

-(void) setage{
    NSLog(@"Student---setage");
}

-(void) setname{
    NSLog(@"Student----setname");
}

@end
實現協議程式碼

    從以上程式碼可以看出類Student實現了協議MyProtocol,因為協議MyProtocol遵循協議ProtocolCom,所以協議MyProtocol有四個方法。所以在Student類中可以實現四個方法。

 

  二. 協議相關約束

    @required 用於表示協議中該方法必須在類中實現,預設[如果不加則預設為@required]

    @optional 用於表示協議中該方法在類中可以選擇實現

    看到這裡貌似比.NET中的要高階點,.NET中interface定義的所有方法在子類中都必須實現。如果用@required標識的方法在子類中沒有實現那麼編譯編譯會報錯,提示該方法必須實現。而@optional則不會。下面這段程式碼就會存在問題:

#import "Student.h"
@implementation Student
-(void) write{
    NSLog(@"write");
}
-(void) eat{
    NSLog(@"eat");
}
-(void) setage{
    NSLog(@"Student---setage");
}
@end
未能實現所有@required標識的方法

    

   三. 同時遵循多個協議

    在.NET中一個類也可以實現多個介面,在Object C中同樣如此,一個類可以實現遵循多個介面,基本語法如下:

    @interface className:parentName<ProtocolName1,ProtocolName2,...>

    ......

    @end

    雖然上面簡單了點,但是還是能夠看明白表達的意思,下面看一段程式碼說明:

    這裡從新定義一個新的協議NewProtocol,裡面有一個必須實現的方法getname

#import <Foundation/Foundation.h>
@protocol NewProtocol <NSObject>
@required
-(NSString*) getname;
@end
NewProtocol協議定義

    然後從新定義一個新的類Children,這個類必須遵循協議NewProtocol和協議MyProtocol ,具體程式碼如下:

#import <Foundation/Foundation.h>
#import "MyProtocol.h"
#import "NewProtocol.h"

@interface Children : NSObject<MyProtocol,NewProtocol>


@end
Children.h 遵循兩個協議

    在Children.m程式碼中要實現兩個協議中必須實現的方法

#import "Children.h"

@implementation Children


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

-(void) setname{
    NSLog(@"Student--setname");
}

-(NSString*) getname{
    return  @"qingyuan";
}
@end
Children.m實現兩個協議程式碼

    下面使用測試程式碼,看看一個類遵循兩個協議的效果:

Children *child=[[Children alloc] init];
        NSString *name=[child getname];
        NSLog(@"name=%@",name);
        [child eat];
        [child setname];
測試程式碼

    在上面的程式碼中可以正常執行,但是要注意如果可選擇實現的方法沒有去實現,而在這裡去呼叫的話會報錯。

 

  四. 正式協議和非正式協議

    說道正式協議和非正式協議,其實只要理解兩個關鍵字@interface 和 @protocol 。先看看下面一個列子

#import <Foundation/Foundation.h>
#import "MyProtocol.h"
#import "NewProtocol.h"

@interface Children : NSObject<MyProtocol,NewProtocol>

-(void) love;

@end
在@interface 定義一個新方法

    在Children.h中定義了一個新的方法love,之前我們也一直這樣寫的,沒有任何問題。再看下面一段程式碼

#import "Children.h"

@implementation Children


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

-(void) setname{
    NSLog(@"Student--setname");
}

-(NSString*) getname{
    return  @"qingyuan";
}
@end
Children.m實現的程式碼

    使用編譯器編輯,程式碼並沒有報錯。在Children.m中沒有love方法的實現。 這個和我們之前所見到的程式碼似乎有點不一樣啊,有點不理解,理論上Children.m中應該實現love方法的。

    上面看到的這種情況,就好比Protocol中的@optional方法,是可以選擇實現的,其實我們就稱作@interface Children : NSObject 就是一個非正式協議。

剛才也注意到了,那是不是Protocol中的@optional標識的方法也就是非正式協議呢。在這裡網路上有些爭議,個人也沒有完全明白,但是個人理解這個還是不一樣的。@protocol是一種既定的規則,如果要做就必須遵循這種規則,而@interface有點象描述,用於描述類是幹什麼的. 而兩者因為都可選擇實現其他的方法,所以感覺有點類似。

 

  五. 協議總結

    Object C中有點特殊的時協議不引用任何類,任何類都可以實現已經定於好的協議。

bool flag1=[child conformsToProtocol:@protocol(NewProtocol)];
        NSLog(@"%d",flag1);
        
        bool flag2=[child conformsToProtocol:@protocol(MyProtocol)];
        NSLog(@"%d",flag2);
        
        bool flag3=[child conformsToProtocol:@protocol(ProtocolCom)];
        NSLog(@"%d",flag3);
判斷某個類是否遵循協議

    從以上程式碼可以看得出,conformsToProtocol 方法用於判斷某個類是否遵循某個協議,返回值為bool型別,即使協議是通過"繼承"過來的也可以。

 

  本文到此結束,學習筆記可能有諸多問題,望請牛人勿噴,菜鳥的學習需要鼓勵!

相關文章