1. 程式人生 > 其它 >OC學習7——類別、擴充套件和協議

OC學習7——類別、擴充套件和協議

1、我麼在呼叫NSLog()方法列印一個物件時,實際上是呼叫了該物件的description方法,這個description方法就和Java中的toString()方法一樣。所以,下面兩行程式碼其實是一樣的

NSLog(@"%@", p) ; 

NSLog(@"%@", [p description]) ;

description方法是NSObject類的一個例項方法,所有的OC都是NSObject類的子類,因此,所有的類都有description方法。description方法方法通常用於實現這樣的一個功能:當程式設計師直接列印該物件時,系統將會輸出該物件的“自我描述”資訊,用以告訴外界該物件具有的狀態資訊。NSObject類提供的description方法總是返回<FKPerson:十六進位制的首地址>,這個返回值並不是先自我描述的功能,因此,如果使用者需要自定義類實現自我描述的功能,則必須重寫NSObject類的description方法。

2、==與isEqual()方法的區別(這一點與Java中的異同點是一致的):

  • ==:如果是比較物件是兩個基本型別,則數值相同就返回true,不同則返回false。如果比較物件是兩個指標變數,則如果兩個指標都指向同一個物件則返回true,否則返回false。
  • isEqual():該方法是NSObject類提供的一個例項方法,因此所有指標變數都可以呼叫這個方法來判斷是否與其他指標變數相等。在預設情況下,isEqual()的判斷方法和==一樣。如果希望採用自定義的相等標準,則可以通過重寫isEqual()方法來實現。NSString已經重寫了isEqual()方法,NSString的isEqual()方法判斷兩個字串相等的標準是:只要兩個字串包含的所有的字元序列相同,則isEqual()返回true,否則返回false。

3、OC中沒有像Java和C++那樣提供抽象類的語法支援,而在實際專案開發中,總有需要用到抽象類的時候,此時就會選擇定義一個父類,並以該父類派生出多個子類,其他程式使用這些類時,實際上返回的是子類的例項,這一系列的類被稱為一個類簇(cluster),這個父類就模擬了抽象類的功能。

OC的動態特性允許使用類別(category)為現有的類新增新房,並且不需要建立子類,不需要訪問原有類的程式碼。通過使用類別就可以動態地為現有的類新增新方法,而且可以將類定義模組化地分不到多個檔案中。類別同樣由介面和實現部分組成,介面和實現部分語法格式如下:

@interface 已有類 (類別名)
//方法定義,類別中只能新增方法,不能新增成員變數
。。。
@end

@implementation已有類 (類別名)
//方法實現
。。。
@end
  • 類別名的命名很隨意,我們自己取定就可以,一般用於描述增加部分的功能
  • 通過類別為制定的類新增新方法之後,這個新方法不僅會影響到該類,還會影響到該類的所有子類,每個子類都會獲得類別擴充套件的方法。
  • 可根據需要為一個類定義多個類別,不同的類別都可對原有的類增加方法的定義。
  • 就程式設計習慣而言,一般習慣將類別的介面檔案命名為“類名+類別名.h”的形式,同樣,實現檔案則命名位“類名+類別名.m”的形式。
//介面部分
#import <Foundation/Foundation.h>

@interface NSArray (Convert)

+(NSMutableArray *)arrayFormNumber:(int)number;

@end

//實現部分
#import "NSArray+Convert.h"

@implementation NSArray (Convert)

+(NSMutableArray *)arrayFormNumber:(int)number{
    NSMutableArray *numberArray=[[NSMutableArray alloc]init];
    while (number) {
        int last=number%10; //取出最後一位;
        number=number/10;
        [numberArray addObject:[NSNumber numberWithInt:last]];       
    }
    return  [numberArray autorelease];
}

@end
  • 使用類別可以對類進行模組化設計:在前面類的設計中,類的介面部分在.h檔案中定義,類的實現部分在.m檔案中定義,且類的實現不能分佈到多個.m檔案中。但是當某個類特別大時,如果將所有實現都放在一個.m檔案中,將會導致這個檔案非常大,以至於維護起來非常困難。如果將一個較大的類進行分模組設計,使用類別是一個不錯的選擇。例如NSWindow類就採用這種設計思想,具體可以在xcode上檢視NSWindow.h檔案。
  • 使用類別來實現私有方法的呼叫:OC中實際上並沒有真正的是有方法,通常而言所說的私有方法指的是沒有在介面部分定義而在實現部分定義的方法,這類方法是不允許被呼叫的,因為沒有通過介面部分向外暴露呼叫介面。在OC中,除了通過NSObject類的performSelector()來執行動態呼叫從而實現呼叫私有方法之外,我們還可以通過使用類別來定義前向引用(其實就是通過類別在介面部分補充定義之前未定義的私有方法),從而實現對私有方法的呼叫。

4、OC中的擴充套件(extension)和類別相似,擴充套件相當於匿名類別,不同的是擴充套件可以定義例項變數。定義擴充套件的語法格式如下:

@interface 已有類 ()
{
    //定義例項變數    
}
//方法定義
。。。
@end
  • 在語法上,擴充套件相當於匿名類別。但是在用法上,類別通常是有單獨的.h和.m檔案,而擴充套件則用於臨時對某一個類的介面進行擴充套件,類實現部分同時實現類介面部分和擴充套件中定義的方法。
  • 在類的擴充套件中,可以額外增加例項變數,也可以用@property來合成屬性,但是在定義類別是則不允許定義成員變數,也不能用@property合成屬性。
 1 #import "vehicle.h"
 2 @interface Vehicle ()
 3 @property(nonatomic, strong) NSString *color;
 4 -(void) drive:(NSString *)name;
 5 @end
 6 
 7 //在實際使用中,通用的做法是省略掉Vehicle_ext.h檔案,而是將其中的內容直接新增在Vehicle.m檔案@implementation前部即可
 8 #import "Vehicle_ext.h"
 9 @implementation Vehicle
10 -(void) drive:(NSString *)name
11 {
12     NSLog(@"交通工具名稱%@,顏色屬性%@",_name,_color);
13 }
14 @end

5、協議(protocol)是OC的一個重要知識點,其作用類似於Java中的介面,用於定義多個類應該遵循的規範。協議提提供任何實習那,協議體現的是規範和實現分離的鬆耦合的設計哲學。

  協議定義的是多個類共同的公共行為規範,這些行為是與外部交流的通道,這就意味著協議裡通常是定義一組公用方法,但是不會為這些方法提供實現,方法的實現則交給類去完成。協議定義時使用@protocol關鍵字,在協議中還有兩個關鍵字@optional and @required,@optional 宣告的方法可以實現,也可以不實現。@required宣告的方法必須實現。具體語法格式如下:

// 定義的協議名稱 遵守協議名稱
@protocol MyProtocol <NSObject>

@required
//定義必選方法

@optional
//定義可選方法

@end


//使用協議
@interface 類名 :父類 <協議1,協議2 ... >
  • 一個協議可以有多個直接父協議,但協議只能繼承協議,不能繼承類
  • 學一種定義的方法只有方法簽名,沒有實現。協議中的方法既可以是類方法,也可以是例項方法。
 1 //
 2 //  Women.h
 3 //  正式協議的定義
 4 //
 5 //  Created by Goddog on 15/1/11.
 6 //  Copyright (c) 2015年 Goddog. All rights reserved.
 7 //
 8 
 9 #import <Foundation/Foundation.h>
10 
11 @protocol Women <NSObject>
12 //定義協議的方法
13 @optional   //可以不實現該介面的方法
14 -(void) pretty;
15 @required   //必須實現該介面的方法
16 -(void) beautiful:(NSString*) count;
17 @end
 1 //
 2 //  Man.h
 3 //  正式協議的定義
 4 //
 5 //  Created by Goddog on 15/1/11.
 6 //  Copyright (c) 2015年 Goddog. All rights reserved.
 7 //
 8 
 9 #import <Foundation/Foundation.h>
10 
11 @protocol Man <NSObject>
12 //定義協議的方法
13 -(void) handsome;
14 @end
 1 //
 2 //  Person.h
 3 //  正式協議的定義
 4 //
 5 //  Created by Goddog on 15/1/11.
 6 //  Copyright (c) 2015年 Goddog. All rights reserved.
 7 //
 8 
 9 #import <Foundation/Foundation.h>
10 #import "Women.h"
11 #import "Man.h"
12 
13 //協議繼承了Women、Man協議
14 @protocol Person <Women,Man>
15 //定義協議的方法
16 -(NSString*) play;
17 @end
 1 //
 2 //  SuperMan.h
 3 //  正式協議的定義
 4 //
 5 //  Created by Goddog on 15/1/11.
 6 //  Copyright (c) 2015年 Goddog. All rights reserved.
 7 //
 8 
 9 #import <Foundation/Foundation.h>
10 #import "Person.h"
11 
12 @interface SuperMan : NSObject<Person>  //實現Person的協議
13 
14 @end
 1 //
 2 //  SuperMan.m
 3 //  正式協議的定義
 4 //
 5 //  Created by Goddog on 15/1/11.
 6 //  Copyright (c) 2015年 Goddog. All rights reserved.
 7 //
 8 
 9 #import "SuperMan.h"
10 #define MAX_CACHE_LINE 10
11 
12 @implementation SuperMan
13 {
14     NSString* playData[MAX_CACHE_LINE];   //使用陣列記錄所有需要快取的資料
15     int dataNum;     //記錄當前的數量
16 }
17 
18 //實現協議方法
19 -(void) pretty
20 {
21     //只要還有漂亮的,繼續上
22     while (dataNum > 0) {
23         NSLog(@"正在和%@玩%@",playData[0],[self play]);
24         //剩下的人數減少
25         dataNum --;
26         //把列隊整體向前移
27         for (int i = 0; i < dataNum; i++) {
28             playData[i] = playData[i + 1];
29         }
30     }
31 }
32 
33 //實現協議方法
34 -(void) beautiful:(NSString *)count
35 {
36     if (dataNum >= MAX_CACHE_LINE) {
37         NSLog(@"人數已滿,不要在上了!");
38     }
39     else
40     {
41         //把人數新增到列隊中
42         playData[dataNum++] = count;
43     }
44 }
45 
46 //實現協議方法
47 -(void) handsome
48 {
49     NSLog(@"英俊");
50 }
51 
52 //實現協議方法
53 -(NSString*) play
54 {
55     
56     return @"遊戲";
57 }
58 
59 @end
 1 #import <Foundation/Foundation.h>
 2 #import "SuperMan.h"
 3 
 4 int main(int argc, const char * argv[]) {
 5     @autoreleasepool {
 6             //建立超人物件
 7         SuperMan* superMan = [[SuperMan alloc] init];
 8         //呼叫協議的方法
 9         [superMan beautiful:@"烏克蘭美女"];
10         [superMan beautiful:@"白俄羅斯美女"];
11         [superMan pretty];
12         [superMan handsome];
13         
14         //建立超人物件,當成Man使用
15         NSObject<Man>* man = [[SuperMan alloc] init];
16         //呼叫Man協議中定義的方法
17         [man handsome];
18         
19         //建立超人物件,當成Women使用
20         id<Women> women = [[SuperMan alloc] init];
21         //呼叫Women協議中定義的方法
22         [women beautiful:@"俄羅斯美女"];
23         [women pretty];
24         //[women handsome];//這樣是不能呼叫的
25     }
26     return 0;
27 }