IOS開發協議使用之──非正式協議和正式協議

來源:互聯網
上載者:User
文章目錄
  •  
  •  
  •  
 轉載地址:http://www.iloss.me/?p=545 

協議分非正式協議和正式協議

先說說非正式協議

非正式協議在Obj-c中關鍵字雖然是interface,但是這個和C#中的借口並不完全相同。

回憶之前學過的內容,我們定義一個類Sample時,會產生一個Sample.h,代碼如下:

#import <foundation foundation.h>

@interface Sample:NSObject {

}

-(void) HelloWorld;

@end

它表明Sample類中,約定了應該有一個名為HelloWorld的方法(注:這裡說的時應該,而不是必須)

它只是一種君子協議。

如果我們在Sample.m中,並不遵守這個約定(即不實現這個方法),編譯器會給出警告。但是還時會編譯成功

中的提示:Incomplete implementation of class “Sample”. 意為:Sample類並未完全實現interface中約定的方法。
這就是obj-c中的協議跟c#中的介面不一樣的地方:在c#中介面是強制必須實現的,否則編譯這一關就過不了,而obj-c雖然在編譯時間會警告,但是最終能編譯通過。

 

正式協議(protocal)
其實就是非正式協議(interface)換了一種寫法而已,看上去更正
規一些,語義上更強烈一些:要求採用該協議的類,”必須”實現協議中約定的方法。但是比較娛樂的是,即使是號稱正式協議,編譯器在編譯時間,遇到不守規矩的
情況,仍然只是給出警告。(當然正式協議也有它存在的意義,後面會提到)
這裡我們定義一個IQuery的協議

IQuery.h

 

@protocol IQuery

-(void) Query:(NSString*) sql;

@end

除了把關鍵字@interface換成了@protocal,其它的基本上沒變化。下面定義一個類DBQuery,並採用這個正式協議
DBQuery.h

#import <Foundation/Foundation.h>

#import “IQuery.h”

@interface DBQuery : NSObject<IQuery> {

}

@end

注意這裡的DBQuery:NSObject<IQuery>,它表明DBQuery繼承自NSObject,同時要實現介面IQuery。
DBQuery.m

#import “DBQuery.h”
@implementation DBQuery
-(void) Query:(NSString *)sql
{
NSLog(@”Query is called. sql:%@”,sql);
}

@end

當然,如果在DBQuery.m中不實現方法Query,也能編譯通過,只是會收到一個警告。
也許到目前為止,你會覺得protocal跟interface比起來,都是類似的概念,protocal設計純屬多餘。其實不然,protocal存在的一個重要意義在於:

式協議(protocal)可以將業務中的方法定義剝離出來,形成一個單獨的檔案,這跟傳統OO中的提取介面是不謀而合的。如果遇到二個系統需要交換數
據,可以制定一套雙方都遵守的protocal,然後這二個系統中都把這個協議檔案添加到項目中,實現它即可。這一功能,非正式協議
(@interface)就做不到。(不信大家可以把NSObject<IQuery>中的IQuery改成其它類的interface
定義名稱試試,編譯根本通不過)
此外,obj-C
2.0中對正式協議還做了一些擴充,允許把正式協議中的方法標識為“必須實現(@requied)”和“可選實現(@optional)”二類,如果協議
中的方法被標識為@optional,即使採用該協議的類不實現這些方法,編譯器也不會給出警告。這賦予了正式協議更多的靈活性。樣本如下:

@protocol IQuery
@required
-(void) Query:(NSString*) sql;
@optional
-(void) HelloWorld;
@end

有了@optional關鍵字以後,其實“非正式協議”在語義上完全可以被“正式協議”所取代,事實上Cocoa中的非正式協議都在逐漸被標有@optional方法的正式協議所代替。
如果你在XCode的代碼中,選中NSObject,右擊–>Jump to Definition,會發現NSObject其實就是一個interface或protocal

選擇protocal NSObject 繼續,會看到NSObject.h檔案中關於protocal NSObject的定義

同樣的,你還可以看到interface NSObject的定義

從這裡可以看到,非正式協議的interface NSObject其實最終採用的還是正式協議protocal NSObject.

也就是說,在obj-c的OO世界中,身為萬物之祖的NSObject其實也就一個”正式協議”,所以從NSObject派生出的所有類,都只是在遵守一個或多個協議而已。

 

另一個話題”泛型”

在obj-c中,一切皆為指標。前面的學習中,我們已經接觸到了一種特殊的類型id,它可以認為是一種特殊的指標:可以指向任何類型的對象。id 再加上正式協議,能夠達到形似c#中泛型的效果(註:只是形似,並非神似)

#import <Foundation/Foundation.h>
#import “IQuery.h”

@interface DBQuery : NSObject<IQuery> {

}

-(void) test:(id<IQuery>) obj;
@end

注意這裡的 -(void) test:(id<IQuery>) obj; 這表明test方法接受一個任意類型的對象做為參數,但是該參數對象必須實現介面IQuery(也可以說成該參數對象必須採用正式協議IQuery),是不是跟c#中的
void test(List<IQuery> obj) 長得很象?

 

自己的理解:

其實協議就相當於Java 中的interface 或者C++ 中的virtual class

舉個例子說說:

首先我們聲明一個協議

@protocol MyProtocol
- (void)myProtocolMethod;
@end

 

@interface TestA
{
TestB<myProtocol>* pB;  // 說明類B應該支援<遵守>myProtocol這個協議
}
@interface TestB: NSObject<myProtocol>{

}

現在我們看如果我們在TestA裡面昨晚了一件事情,然後要通知TestB。那就要通過myProtocol來實現,那通過pB我們就可以給myProtocol發通知,那TestB也就收到訊息了

下面再附上一個用協議實現回呼函數的例子,(網上轉來的,但可以協助我們理解)

在編寫android開發時,最常用的就是回呼函數。自己編寫回呼函數,實現動態載入資料,載入完資料之後就利用回呼函數通知給前台頁面,顯示相應資料的介面。在iphone中利用協議可以很容易的實現回呼函數,後台載入資料,然後顯示在前台頁面。

實現一個顯示文字為測試的視圖,然後經過3秒鐘測試文字變為回呼函數文字。相應的如下:

實現的代碼如下:

#import <UIKit/UIKit.h>
@protocol NoteDelegate     //聲明協議
//回呼函數
-(void)messageCallBack:(NSString *)string;
@end

調用協議:

#import <Foundation/Foundation.h>
#import “NoteDelegate.h”
@interface ManagerMessage : NSObject {
id<NoteDelegate> *noteDelegate;
}
@property (nonatomic,retain) id<NoteDelegate> *noteDelegate;    //@property先行編譯命令的作用是自動聲明屬性的 setter 和getter方法
-(void)startThread;
@end

#import “ManagerMessage.h”
@implementation ManagerMessage
@synthesize noteDelegate;
//開始一個線程
-(void)startThread
{
//啟動線程
[NSTimer scheduledTimerWithTimeInterval:3
target:self
selector:@selector(targetMethod:)
userInfo:nil
repeats:NO];
}
-(void)targetMethod:(NSString *)string
{
if (self.noteDelegate!=nil) {
//完成線程 調用回呼函數
[self.noteDelegate messageCallBack:@"回呼函數"];    //在這通過協議進行回調
}
}
@end

前台頁面實現:

#import “IphoneDeleteViewController.h”
#import “ManagerMessage.h”
@implementation IphoneDeleteViewController
@synthesize textView;

//回呼函數
-(void)messageCallBack:(NSString *)string
{
self.textView.text=string;    //前台收到回調資訊 給了textView
}

- (void)viewDidLoad {
[super viewDidLoad];
self.textView.text=@”測試”;
ManagerMessage *message=[[ManagerMessage alloc] init];
//通知調用協議
message.noteDelegate=self;
[message startThread];
[message release];
}

- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
}

- (void)viewDidUnload {
self.textView=nil;
}

- (void)dealloc {
[self.textView release];
[super dealloc];
}

@end

 
相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.