天天看點

【Objective-C】類别(拓展類)、協定

一、類别(Category)簡介

 OC中類别功能強大,它能夠在不使用繼承的情況下向現有的類添加新的方法。特别是在沒有類的源代碼的情況下,通過使用類别依然能夠向該類添加新的方法。

 類别的主要有兩個作用,一是向類添加新的方法以拓展類的功能,二時将類的實作部分分布發哦多個檔案中。

二、聲明類别并實作類别方法

1. 類别的聲明與實作的格式如下

#import "目标類名.h"

@interface 目标類名 (類别名稱)

// 方法聲明區

@end


@implementation 目标類名 (類别名稱)

// 方法實作區

@end
           

其實類别的聲明與實作格式與類的聲明和實作格式類似。差別就是類别聲明後面會加上小括号,而類接口聲明沒有小括号。方法聲明區中給出了類别中的方法聲明,這些方法會附加到目标類中。注意:在附加之後這些方法與類的其它方法沒有任何差別,他們也能夠通路類的成員變量,或是繼承到目标類的子類中。但是,如果目标類和類别都定義了一個簽名完全一樣的方法,則類别中的方法會替換類中定義的方法。如果有兩個類别都定義了一個簽名完全一樣的方法,則調用哪一個方法是不用确定的。另外類中隻能定義方法,不能定義成員變量。

2. 拓展類的功能:

    有時候根據需要,比如說一個項目有不同的子產品,要配置設定給不同的人做。這時候就可以使用類别,我們可以定義多個附加到目标類的類别,并在該類别中實作需要實作的方法。

建立檔案---oc file---類名、file type、附加的類名稱

#import "Student.h"   //導入這個檔案是位了要知道目标類中有哪些方法
//#import <Foundation/Foundation.h>     //不需要導入這個檔案了

// ()代表着一個分類
// ()中的Test代表着分類的名稱
// 不使用@class是因為“分類”是給原類拓展一些方法

@interface Student (Test)

- (void)test2;

@end
           
#import "Student+Test.h"

@implementation Student (Test)

- (void)test2 {
    NSLog(@"這個代表調用的test2");
    
}


@end
           
【Objective-C】類别(拓展類)、協定

3. 拆分類的實作:

    除了拓展類的行為之外,類别還有一個作用就是将類的實作分成若幹部分。

三、協定(代理)--- 隻有聲明.h沒有實作.m,需要其他的類去實作

 oc中的協定與java、c#中的借口以及c++中的抽象類相類似,用于定義公共接口,并承諾類需要實作協定中規定的方法。使用協定中最大的好處就是它能夠有效拓展程式的功能。比如說:,通用串行總線(Universal Serial Bus, USB)就是一個協定,它能夠讓計算機周邊裝置連接配接标準化。現在的計算機都配備了USB接口,這樣能夠有效拓展計算機的功能。USB協定定義了接口的尺寸、電壓、電流大小等規範,隻要裝置符合USB協定就可以介入到計算機中使用。至于裝置的具體作用可以由廠家自己進行設計規劃。

 java、c#接口、c++抽象類要求實作它的非抽象類必須實作它規定的方法。objective-c中的協定更加靈活,他可以規定哪些方法必須實作,那些方法可以有選擇性的地實作。

1. 簡介:

    1. Protocol:就是一個用途,用來聲明一大堆方法(不能聲明成員變量),不能寫實作;

    2. 隻要某個類遵循了這個協定,就擁有了這個協定中的所用方法;

    3. 隻要父類遵守某個協定,那麼子類也遵循;

    4. Protocol聲明的方法可以讓任何類去實作,protocol就是協定;

    5. OC不能繼承多個類(單繼承)(:),但是能夠遵守多個協定。(<>)

    6. 基協定:<NSObject>是基協定,是最根本的協定,其中聲明了很多基本的方法;

    7. 協定可以遵守協定,一個協定遵守了另一個協定,就可以擁有另一份協定中的方法聲明;

2. 聲明協定

    關鍵字Protocal,和類的外部接口聲明類似,協定定義在@protocol與@end指令之間。@protocol後接協定名稱。并使用@required與@optional規定哪些方法必須由采用該協定的類實作,哪些方法可以有選擇性地實作,預設為@required(必須要實作)。

格式:

@protocol 協定名 <父協定>

定義方法

@end

注:定義協定的關鍵字是@protocol,同時協定也是可以繼承父協定的。

建立一個協定:

#import <Foundation/Foundation.h>

// MyProtocol就是協定,這個協定遵守基協定<NSObject>
@protocol MyProtocol <NSObject>
// 在協定中可以聲明很多有用的方法
// @property int age; 在協定中不能聲明成員變量,隻能是聲明方法,也不能實作方法
@required
// @required關鍵字主要用于程式員之間的交流,要求實作
- (void)pint;
- (void)haha;
@end

@interface MyProtocol : NSObject

@end
           

遵守協定:

#import <Foundation/Foundation.h>
#import "MyProtocol.h"
// 在類的聲明中加入協定的頭檔案

// Person類的聲明,這個類繼承了NSObject類,遵守MyProtocol協定
@interface Person : NSObject <MyProtocol>

@end
           

或者按照下面的實作:

#import <Foundation/Foundation.h>
// #import "MyProtocol.h"
// 在類的聲明中加入協定的頭檔案

// 方式二使用一種方式,與前面将的@class前向聲明功能一樣;在.m檔案中在進行導入也是可以
@protocol MyProtocol;

// Person類的聲明,這個類繼承了NSObject類,遵守MyProtocol協定
@interface Person : NSObject <MyProtocol>

@end
           

完成協定中聲明的方法的實作:

#import "Person.h"

@implementation Person
// 在這裡進行遵守的協定裡所聲明的方法的實作

- (void)pint {
    NSLog(@"nihao!");
}

- (void)haha {
    NSLog(@"nibuhao!");
    
}

@end
           

測試程式:

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

int main(int argc, const char *argv[])
{
    @autoreleasepool {
        Person *per = [[[Person alloc] init] autorelease];
        [per pint];
        [per haha];
    }
}

           

3. 注意點

  1.協定的定義

     @protocol 協定名稱 <NSObject>

     //方法聲明清單

     @end;

  2.如何遵守協定

  (1)類遵守協定

     @protocol 類名 :父類名 <協定名稱1,協定名稱2>

     @end

  (2)協定遵守協定

    @protocol 協定名稱 <其他協定名稱>

    @end;

  3.協定方法聲明中的關鍵字

  (1)required (預設)要求實作,若沒有實作則警告但不報錯

  (2)Optional 不要求實作

  4.定義變量時遵守協定的限制(隻能是對象)

     類名<協定名稱> *變量名    NSObject<.Myprotocol> *obj;

     Id  <協定名稱>  變量名   id  <.Myprotocol> obj1;

  5.Property中聲明的屬性也可以做遵守協定的限制

     @property (nonatomic ,strong ) 類名<協定名稱> *屬性名;

     @property (nonatomic ,strong ) id<協定名稱>  屬性名;

  6.補充:協定本身寫在頭檔案中,但也可以定義在任何地方。當這個協定隻有這個類使用遵守時,一般把協定寫在這個類裡面(同一檔案),當這個協定需要多個類去實作時,就寫在外邊單獨的檔案中(建立)。

4. 實作協定

    協定定義後,需要其他類遵循(實作)協定。在類的外部接口中,可以定義其他類遵從哪些協定。類不允許繼承多個類,但是類允許遵從多個協定。當某個類需要遵從多個協定時,可以在類的接口中的@interface指令後給出,協定名稱必須位于尖括号内,多個協定名稱之間使用逗号分開。

5. 使用協定限制對象類型與行為

    協定可以限定對象類型,并在程式的編譯期間給出警告。

6. 在程式中我們跟難知道程式是否實作了協定這一功能。這時候需要我們對協定進行判斷。

// conformToProtocol: 判斷是否遵守了某協定
        if ([stu conformsToProtocol:@protocol(Read)]) {
            NSLog(@"對象遵守了協定");
        }
        
        // 判斷是否遵守了某内容
        if (![stu respondsToSelector:@selector(haha)]) {
            NSLog(@"對象沒有實作這個方法");
        }
           

7. 限制對象實作協定

// 協定限制
void demo03()
{
    // 限制它遵守協定    會報錯 意思是不比對
    // NSObject<MyProtocol> *peo = [[NSObject alloc] init];
    
    NSObject<MyProtocol> *peo = [[Person alloc] init];
    peo = nil;
    
    // id<MyProtocol> *peo1 = [[Person alloc] init];  id 就是相當于 -- 類 *
    id<MyProtocol> peo1 = [[Person alloc] init];
    peo1 = nil;
    
    
}
           

**:協定的相關案例後面的博文中會繼續分享。= =

繼續閱讀