2014年8月14日 星期四

Custom Delegate programmatically using Swift and Object-C language

【說明】

此份筆記紀錄如何自訂Delegate,並且使用代理人機制。

情境:當被NavigationController包著時,A ViewController要接收B ViewController所回傳的資料。B ViewController是擁有代理人機制的Controller,A ViewController要成為B ViewController的代理人。

B ViewController要成為擁有代理人機制必須有三步驟:
1.  建立自訂的Protocol
2.  建立Delegate實體變數
3.  當事件發生時,發送message給代理人

A ViewController要成為B ViewController的代理人必須有三步驟:
1.  指定代理人是誰
2.  代理人必須採納Protocol
3.  代理人必須實作method


【專案開發步驟】

建立專案:

使用Single View Application模板建立一個名為CustomDelegate的專案,使用iPhone裝置。

設計使用者介面:

替View加入NavigationController,並完成介面的設計,並將會用到的元件與對應的ViewController做連結,如下圖所示。

設計使用者介面
建立並修改B ViewController:

新增Class,並取名為DetailViewController,並與Storyboard內的ViewController做連結,如下圖所示。

<Swift>
宣告Storyboard內的ViewController的Class是誰_Swift
<Object-C>
宣告Storyboard內的ViewController的Class是誰_Object-C

擁有代理人機制步驟1,建立自訂的Protocol。

<Swift>
在DetailViewController.swift內新增程式碼,程式碼必須撰寫在現有的Class外,如下所示。

protocol DetailViewControllerDelegate {
    func detailViewControllerWithName(name: NSString)
}

class DetailViewController: UIViewController {
}

<Object-C>
在DetailViewController.h內新增程式碼,程式碼必須撰寫在@interface外,如下所示。

@protocol DetailViewControllerDelegate
-(void)detailViewControllerWithName:(NSString*)name;
@end

@interface DetailViewController : UIViewController
@end

擁有代理人機制步驟2,建立Delegate實體變數,如下所示。

<Swift>
在DetailViewController.swift內新增程式碼,程式碼必須撰寫在現有的Class內,如下所示。

class DetailViewController: UIViewController {
    var delegate: DetailViewControllerDelegate?
}

<Object-C>
在DetailViewController.h內新增程式碼,程式碼必須撰寫在@interface內,如下所示。

@interface DetailViewController : UIViewController
@property(nonatomic,weak)id<DetailViewControllerDelegate> delegate;
@end

擁有代理人機制步驟3,當事件發生時,傳送message給代理人。

<Swift>
在DetailViewController.swift內新增程式碼,程式碼必須撰寫在現有的Class內,如下所示。

@IBAction func click(sender: UIButton) {
    navigationController.popToRootViewControllerAnimated(true)
    delegate?.detailViewControllerWithName(nameField.text)
}

<Object-C>
在DetailViewController.m內新增程式碼,程式碼必須撰寫在@implemtation內,如下所示。

- (IBAction)click:(UIButton *)sender {
    [self.navigationController popToRootViewControllerAnimated:YES];
    [self.delegate detailViewControllerWithName:self.nameField.text];
}

修改A ViewController:

將Class名改為MainViewController,並與Storyboard內的ViewController做連結,如下圖所示。

<Swift>
宣告Storyboard內的ViewController的Class是誰_Swift
<Object-C>
宣告Storyboard內的ViewController的Class是誰_Object-C

成為代理人步驟1,指定代理人是誰。
利用prepareForSegue這個method得到DetailViewController這個Class指標。

<Swift>
在MainViewController.swift內新增程式碼,程式碼必須撰寫在現有的Class內,如下所示。

override func prepareForSegue(segue: UIStoryboardSegue!, sender: AnyObject!) {
    let detailViewController: DetailViewController = segue.destinationViewController as DetailViewController
    detailViewController.delegate = self
}

<Object-C>
在MainViewController.m內新增程式碼,程式碼必須撰寫在@implemtation內,且需#import "DetailViewController.h",如下所示。

-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
    DetailViewController *detailViewController = segue.destinationViewController;
    detailViewController.delegate = self;
}

成為代理人步驟2,代理人必須採納Protocol。

<Swift>
在MainViewController.swift內新增程式碼,如下所示。

class MainViewController: UIViewController, DetailViewControllerDelegate {
}

<Object-C>
在MainViewController.m內新增程式碼,如下所示。

@interface MainViewController ()<DetailViewControllerDelegate>
@end

成為代理人步驟3,代理人必須實作method。
實作我們剛剛在自訂的Protocol內所宣告的method。

<Swift>
func detailViewControllerWithName(name: NSString) {
    nameLabel.text = name
}

<Object-C>
-(void)detailViewControllerWithName:(NSString *)name {
    self.nameLabel.text = name;
}
當DetailViewController內的Done被按下後會觸發click的function,會執行detailViewControllerWithName這個method,並會將nameField的文字傳送給Delegate。當代理人實作這個method時就會收到從DetailViewController傳過來的文字,並用name作為代表。所以我們只要把傳過來的文字顯示在我們的Label上即可。


【執行結果】

    
    


【專案範例】

沒有留言:

張貼留言