1. 程式人生 > >黑馬程式設計師——OC的Category和Protocol

黑馬程式設計師——OC的Category和Protocol

Category

一、基本概念

  1. 分類的作用:

    • 在不修改原有的類的基礎上增加新的方法
    • 一個龐大的類可以分模組開發,便於維護
    • 一個龐大的類可以由多個人來編寫,更有利於團隊合作
  2. 使用類別的目的

    • 對現有類進行擴充套件:對自定義的類甚至是框架中的類進行擴充套件,從而實現專案特殊需求。
    • 作為子類的替代手段:不需要定義和使用一個子類,可以通過類別直接向已有的類中增加方法。
    • 對類中的方法歸類:利用category把一個龐大的類劃分為小塊來分別進行開發,從而更好的對類中的方法進行更新和維護。
  3. 關於非正式協議

    為NSObject新增的分類就稱作非正式協議。非正式協議一般不需要進行實現,而是在子類中進行方法的重寫。

二、分類的使用

1.分類的實現步驟

  1. 宣告

    格式:

    @interface 待擴充套件的類名 (分類的名稱)

    @end

  2. 實現

    格式:

    @implementation 待擴充套件的類名 (分類的名稱)

    @end

  3. 檔案的命名格式:

    待擴充套件的類名+分類名稱

  4. 使用

    與使用類中原有的方法一樣,用方括號呼叫。

2.程式碼舉例

假設現在已經有Person類,要建立一個Person的類擴充套件,首先在當前target中新建Objective-C File,檔名填寫分類名稱,File Type選擇Category,類名填寫要擴充套件的類名。檔案建立好之後,就像使用普通類一樣,在.h檔案中宣告方法,在.m檔案中實現方法。例如:

/******Person+play.h*******/
#import "Person.h"

@interface Person (play)
-(void)paly;
@end
/******Person+play.m*******/
#import "Person+play.h"

@implementation Person (play)
-(void)paly{
    NSLog(@"playing");
}
@end

這樣在使用Personm類時就可以直接呼叫play方法了。

但是Category也有他的侷限:

  • 不能在Category中擴充套件類的成員變數
  • 名稱衝突,當Category中實現的類與已有方法重名時,會完全取代已有方法。

三、類擴充套件(延展)

1.類擴充套件的作用

分類(Category)的一個缺陷是隻能擴充套件方法而不能擴充套件成員變數,類擴充套件(Class Extension)可以實現向原有類中新增成員變數。

2.實現方法

類擴充套件實際上是一個特殊的分類,在定義@interface的時候不對分類進行命名,這個分類就成了一個類擴充套件。建立類擴充套件的時候在新建檔案時File Type選擇Extension即可。例如:

/******Person_body.h*******/
#import "Person.h"

@interface Person ()
{
    float _weight;
    float _height;
}
@end

3.注意

  • 類擴充套件只有@interface部分而沒有@implementation
  • 類擴充套件也可以新增方法,但是方法的實現要寫在類的.m檔案中
  • 可以改變變數的讀寫許可權

Protocol

一、基本概念

1.Protocol的作用

Protocol(協議)是包含了方法和屬性的有名稱列表。採用協議的類必須實現協議要求實現的方法,否則編譯器會報錯。

2.協議的使用流程

  1. 定義協議(在.h檔案中)

    在當前target中新建Objective-C檔案,File Type選擇Protocol。

    格式:

    @protocol 協議名稱 <NSObject>  //預設遵守NSObject協議
    //方法宣告列表 
    @end;
  2. 採用(遵守)協議

    • 類遵守協議

      建立類的時候遵守某個或者某幾個協議

    @interface 類名 : 父類 <協議名稱1,協議名稱2>
    @end
    • 協議遵守協議

      協議也可以遵守一個或多個其他協議

    @protocol 協議名稱 <其他協議名稱1,其他協議名稱2>
    @end
  3. 實現協議要求實現的方法

3.協議的注意事項

  • Protocol:就一個用途,用來宣告方法(不能宣告成員變數),不能寫實現。
  • 只要某個類遵守了這個協議,就擁有了這個協議中的所有方法宣告。
  • 只要父類遵守了某個協議,那麼子類也遵守。
  • Protocol宣告的方法可以讓任何類去實現
  • OC不能繼承多個類(單繼承)但是能夠遵守多個協議。
  • 基協議:\

4.可選和必須

在協議中,可以定義一個方法的宣告是否必須被實現,通過關鍵字@optional和@required實現,例如:

@protocol 協議名稱 <NSObject> 
@optional
-(void)run;//可選實現,不是必須的
@required
-(void)eat;//必須實現
@end;

預設是@required。

5.型別限制

當建立一個物件時,希望這個物件必須遵守了指定的協議,就需要使用型別限制。

  • 物件賦值時的型別限制

    格式:類名<協議名稱> *變數名

    例如:Person<run> *p = [Person new];//只有Person類確實遵守了run協議編譯器才不會報錯

  • 關聯關係下的型別限制

    使用@property宣告成員變數時,如果成員變數是一個物件,則可以使用型別限制對物件進行限制,格式如下:@property 類名<協議名> *變數名;

    例如:@property Pet<dog> *pet;//只有遵守了dog協議的Pet類才能作為該類的成員變數

  • 使用id儲存物件時的型別限制

    格式:id <協議名稱> 變數名

    例如:id<run> p = [Person new]

二、程式碼實現

/******studyProtocol.h******/
@protocol studyProtocol <NSObject>
-(void)studyOC;
@end
/******playProtocol.h******/
@protocol playProtocol <NSObject>
-(void)playPCgame;
@optional
-(void)playBasket;
@end
/******Person.h******/
#import <Foundation/Foundation.h>
#import "playProtocol.h"
@interface Person : NSObject<playProtocol>
@end
/******Person.m******/
#import "Person.h"

@implementation Person
-(void)playPCgame{
    NSLog(@"Playing PC game now");
}
@end
/******Student.h******/
#import "Person.h"
#import "studyProtocol.h"
@interface Student : Person<studyProtocol>
@end
/******Student.m******/
#import "Student.h"

@implementation Student
-(void)studyOC{
    NSLog(@"Studying OC now");
}
@end
/******main.m******/
#import <Foundation/Foundation.h>
#import "Person.h"
#import "Student.h"
int main(int argc, const char * argv[]) {
    @autoreleasepool {
        Person<playProtocol> *p = [Person new];
        [p playPCgame];//->Playing PC game now
        Student *stu = [Student new];
        [stu playPCgame];//->Playing PC game now
        //Person<studyProtocol> *p2 = [Person new];編譯器警告,因為Person類沒有遵守studyProtocol協議
        Student<studyProtocol> *stu2 = [Student new];
        [stu2 studyOC];//->Studying OC now
    }
    return 0;
}