看板 Knuckles_note
作者 Knuckles (站長 那克斯)
標題 [Xcode] 建立類別的 protocol 使用 delegate 函數
時間 2014年10月05日 Sun. PM 11:41:42


當有需要在類別中,建立一組讓另一個類別可以執行的成員函數
要使用 protocol 宣告 delegate 函數

例如在 Master-Detail 的架構下,有兩個頁面:
MasterViewController 與 DetailViewController

Master 裡有個成員變數 _name ,會用個 Label 顯示使用者名稱
點一下會連進 Detail,並將 _name 的值傳給 Detail
在 Detail 裡有 Text 可以修改使用者名稱

當在 Detail 裡修改了使用者名稱後,回到 Master 卻發現使用者名稱沒有變
要如何在 Detail 裡修改名稱後,通知 Master 將使用者名稱也變新的呢?


在 Objective-C 裡是用一個特別的 delegate 函數來處理這問題

delegate 就是委任的意思,因為 Detail 沒有辦法改 Master 裡的成員變數 _name
所以產生一個 delegate 函數,將這函數的實作放在 Master 裡

當 Detail 需要的時候可以呼叫並傳值給放在 Master 裡的 delegate 函數
而 Detail 的 delegate 函數因為放在 Master 裡,所以可以存取 Master 的成員變數


實際的作法為:

先在 DetailViewController.h 用 @protocal 宣告 delegate 函數

在 @interface DetailViewController : UIViewController 的上一行加上
@protocol DetailViewControllerDelegate <NSObject>
- (void)didChangeName:(NSString *)name;
@end


在 @interface DetailViewController : UIViewController 的下一行加上
@property (nonatomic, weak) id <DetailViewControllerDelegate> delegate;


這邊我們在 DetailViewController 類別裡新增了一個成員變數 delegate
且宣告了一個 delegate 函數 -didChangeName:

修改 DetailViewController.m
當在 DetailViewController 的某個成員函數中修改了使用者名稱後,執行
[self.delegate didChangeName:name]

將修改後的 name 傳給這個 delegate 函數

而這個 delegate 函數的實作是寫在 MasterViewController
所以可以修改 MasterViewController 的成員變數


修改 MasterViewController.h
加上
#import "DetailViewController.h"

在 @interface MasterViewController : UITableViewController
這行尾端加上
<DetailViewControllerDelegate>


修改 MasterViewController.m
加上可以讓 DetailViewController 呼叫的 delegate 函數

- (void)didChangeName:name{
	
//修改 MasterViewController 的成員變數 _name
	
_name = name;
	
[self.tableView reloadData];
}


在 storyboard 中,設定連結 MasterView 與 DetailView 的 segue
將 identifier 改為 ChangeName
然後修改 MasterViewController.m 的 -prepareForSegue:sender: 為

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
    if ([segue.identifier isEqualToString:@"ChangeName"]) {
        DetailViewController *detailViewController = segue.destinationViewController;
        detailViewController.delegate = self;
    }
}


就是在用 segue 切換頁面時
將 MasterViewController 的指標存在 DetailViewController 裡的成員變數 delegate

這樣 DetailViewController 就可以用 [self.delegate didChangeName:name]
呼叫放在 MasterViewController 的 delegate 函數了

--
--
※ 作者: Knuckles 時間: 2014-10-05 23:41:42
※ 編輯: Knuckles 時間: 2015-03-12 14:53:57