視圖之間的關係,不僅僅是跳轉,更重要的是視圖之間數據的傳遞。當視圖A 發生變化時,如何將這個變化告知視圖B 呢? 舉個例子吧。
如下圖所示。
這是一個計算器App,支持函數的圖形展示。 點擊右上角的按鈕,可彈出函數 列表。 這個列表是一個TableView; 函數圖形的展示是另一個視圖,我們稱之爲 GraphicView。 這個實例所展示的是: 當在Tableview選擇不同的函數時,函數的繪製圖形會隨之改變。這裏要解決的關鍵問題是, 如何將所選擇的函數告知 函數圖形視圖?
先說明下,這是基於Storyboard 創建的工程。 工程本身有些複雜,我們不再從頭講起,這裏着重講解 @protocol 的使用。
通常,一個delegate的使用過程,需要經過五步:
1. 創建一個 delegate;
2. 委託者聲明一個delegate;
3. 委託者調用delegate內的方法(method);
4. 被委託者設置delegate,以便被委託者調用;
5. 被委託者實現Delegate 所定義的方法。
接下來,我們來一步一步實現:
1.1 第一步: 創建一個delegate
在 .h 文件中, 通過 @protocol 創建一個 delegate:
@protocol CalculatorProgramsTableViewControllerDelegate
@optional
- (void)calculatorProgramsTableViewController:
(CalculatorPorgramTableViewController *)sender
choseProgram:(id)program;
@end
代碼解釋:
@protocol CalculatorProgramsTableViewControllerDelegate
用來創建一個delegate。 這個delegate 中有一個方法:
(void)calculatorProgramsTableViewController
@optional 表明,這個方法是不要求一定實現,是可選的。
小貼士:
這裏需明確一個概念, 雖然通過@protocol 定義了一個delegate,但不能說, delegate 就是protocol。 前面提到過,delegate是一種架構設計模式。 在iOS中,它是通過@protocol 來實現的。
1.2 第二步: 委託者聲明一個delegate
在TableView 的 .h 文件中 (CalculatorProgramsTableViewController.h), 將之前創建的delegate 通過@property 進行聲明。 代碼如下:
@interface CalculatorProgramsTableViewController : UITableViewController
...
// Define a property delegate
@property (nonatomic, weak) id<CalculatorProgramsTableViewControlerDelegate>
delegate;
...
@end
添加這幾行代碼後 , TableView 便擁有了Delegate。 有了Delegate, TableView就可以發消息了。 僅僅是可以發消息了,但還沒有發。 下一步,Tableview 開始發送消息。
1.3 第三步:委託者調用delegate內的方法
我們的目標是: 當在TableView 上選擇不同的函數時, TableView 將這個所選定的函數,告知繪製函數圖形的GraphicView。
這一步,TableView 通過調用delegate的方法,發送消息。代碼實現如下:
#progma mark - UITableViewDelegate
- (void)tableView:(UITableView *)tableView
didSeelectRowAtIndexPath:(NSIndexPath *)indexPath
{
id program = [self.programs objectAtIndex:indexPath.row];
[self.delegate calculatorProgramsTableViewController:self
choseProgram:porgram];
}
代碼解釋:
注意到 高亮部分的 self.delegate 了吧。 UITableView 就是通過這個之前定義的delegate 發送消息的。具體做法是: UITableViewController 調用delegate 中所定義的函數。通過這個函數的調用, 實現了消息的發送。但發到哪裏去了,還不得而知。這是因爲, self.delegate 還沒賦值呢。
接下來,要做的是: 將 self.delegate 設置爲GraphicView。
1.4 被委託者設置delegate,以便被委託者調用;
前面談到, UITableViewController 中的self.delegate 還沒有賦值。既然TableView 想把值傳給Graphicview, 那就應該在calculatorGraphViewController.m 文件中設置delegate。 也就是說,讓Graphicview 成爲Tableview的delegate。
代碼如下:
@implementation CalculatorGraphViewController
...
- (void)prepareForSegue:(UIStoryboardSegue *)segue
sender:(id)sender
{
if ([segue.identifier isEqualToString:@"Show Favorite Graphics"]) {
NSArray * programs = [[NSUserDefaults standardUserDefaults]
objectForKey:FAVORITES_KEY];
[segue.destinationViewController setPrograms:programs];
[segue.destinationViewController setDelegate:self];
// set delegate
}
}
代碼解釋:
但點擊Graphicview 右上角的button 時, 會彈出一個Tableview。同時,在這段代碼的最後一行,將CalculatorGraphViewController 設置爲Tableview 的delegate。
通過這個設置, Tableview便可以調用Graphicview 所遵循的delegate 的的方法。
Delegate 的這個方法還沒實現呢, 趕緊實現它吧。
1.5 被委託者實現Delegate 所定義的方法。
還記得那個神祕的 <> 吧。 通過以下代碼,讓GraphicViewController 來遵循這個delegate。
// .h to implement the protocol
@interface CalculatorGraphViewController :NSObject
<CalculatorProgramsTableViewControllerDelegate>
...
@end
這是delegate使用的最後一步了, 我們在segue的controller 文件中,實現這個protocol所定義的方法。代碼如下:
// implement delegate method
- (void)calculatorProgramsTableViewController:(CalculatorProgramsTableViewController *)sender
chooseProgram:(id)program
{
self.calculatorProgram = program;
}
1.6 小結
通過以上delegate 五部曲的演示,我們對delegate的機制,清楚些了吧。 Delegate 實現了不同視圖之間的數據交互。 Delegate 屬於事件驅動的範疇。只有當某一事件觸發時,delegate 才被調用。
在Cocoa 框架中, 雖然數據存儲和訪問的方式有多種, 但delegate 所獨有的數據交互模式是無可替代的。
注:以上來自斯坦福iOS 教學。 這是一個經典的 delegate 應用案例。