Coder_CYX
導(dǎo)讀:
iOS開(kāi)發(fā)中,你肯定遇到過(guò)控制器之間的值或模型的傳遞,本文將從兩種創(chuàng)建控制器的方式&兩種值傳遞的方向,分別介紹了如何進(jìn)行控制器之間值傳遞的方法及步驟。因?yàn)椴┲髦R(shí)水平有限,這只是實(shí)現(xiàn)值傳遞的其中幾種方式,如果您有更好的建議,歡迎提出,大家一起討論,共同進(jìn)步。
純代碼方式
控制器之間傳值
- 兩個(gè)要點(diǎn):
- 1.接收方一定要有屬性去接收
- 2.傳遞方需要拿到接收方,進(jìn)行直接賦值
順傳
- 上一級(jí)控制器傳遞給下一級(jí)控制器。
- 實(shí)現(xiàn)策略:直接拿到下一級(jí)控制器,拿到以后,做什么事情都行(對(duì)其屬性賦值)
- 實(shí)現(xiàn)代碼:
上一級(jí)控制器(傳遞方):
#import "CYXContactViewController.h"
#import "CYXContact.h"
#import "CYXEditViewController.h"
@implementation CYXContactViewController
// 準(zhǔn)備好segue線之后,跳轉(zhuǎn)之前會(huì)調(diào)用
// 做一些數(shù)據(jù)之間的傳值
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
//獲取目標(biāo)控制器
CYXEditViewController *editVc = segue.destinationViewController;
// 獲取當(dāng)前選中的角標(biāo)
NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];
// 獲取選中的cell對(duì)應(yīng)的模型
CYXContact *cont = self.contactArr[indexPath.row];
// 傳遞選中的cell對(duì)應(yīng)的模型
editVc.contact = cont;
}
@end
下一級(jí)控制器(接收方):
#import <UIKit/UIKit.h>
@class CYXContact;
@interface CYXEditViewController : UIViewController
/** 用于存儲(chǔ)聯(lián)系人頁(yè)傳來(lái)的模型 */
@property (strong, nonatomic) CYXContact * contact;
@end
逆?zhèn)?/h4>
- 下一級(jí)控制器傳遞給上一級(jí)控制器。
- 實(shí)現(xiàn)策略:使用代理。上一級(jí)控制器作為下一級(jí)控制器的代理,監(jiān)聽(tīng)下一級(jí)控制器的事情。
- 實(shí)現(xiàn)代碼:
上一級(jí)控制器(接收方)
**//1.遵守協(xié)議**
@interface CYXContactViewController ()<CYXAddViewControllerDelegate>
**//2.設(shè)置代理為self控制器**
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
CYXAddViewController *addVc = segue.destinationViewController;
addVc.delegate = self;
}
**//3.實(shí)現(xiàn)代理方法**
- (void)addViewController:(CYXAddViewController *)addVc didAddContact:(CYXContact *)contact{
[self.contactArr addObject:contact];
[self.tableView reloadData];
}
下一級(jí)控制器(傳遞方)
.h 文件:
#import <UIKit/UIKit.h>
@class CYXContact,CYXAddViewController;
@protocol CYXAddViewControllerDelegate<NSObject>
@optional
**//1.定義代理方法**#
- (void)addViewController:(CYXAddViewController *)addVc didAddContact:(CYXContact *)contact;
@end
@interface CYXAddViewController : UIViewController
**//2.聲明代理屬性**
@property (nonatomic,weak) id<CYXAddViewControllerDelegate> delegate;
@end
.m 文件:
@implementation CYXAddViewController
// 逆?zhèn)?// (1)在跳轉(zhuǎn)之前,在傳遞方把接收方先保存起來(lái)
// (2)等需要真的給接收方傳值的時(shí)候,直接拿到它傳值
// 點(diǎn)擊添加按鈕的時(shí)候調(diào)用
- (IBAction)addContact:(id)sender {
// 把姓名和電話文本框的內(nèi)容包裝成模型
CYXContact *contact = [CYXContact contactWithName:_nameField.text phone:_phoneField.text];
**// 3.調(diào)用代理方法,通知代理接收聯(lián)系人模型**
if ([_delegate respondsToSelector:@selector(addViewController:didAddContact:)]) {
[_delegate addViewController:self didAddContact:contact];
}
// 回到上一個(gè)控制器
[self.navigationController popViewControllerAnimated:YES];
}
Storyboard方式
認(rèn)識(shí)Segue
-
什么是Segue
- Storyboard上每一根用來(lái)界面跳轉(zhuǎn)的線,都是一個(gè)UIStoryboardSegue對(duì)象(簡(jiǎn)稱Segue)
-
Segue的屬性
- 唯一標(biāo)識(shí):
@property (nonatomic, readonly) NSString *identifier; - 來(lái)源控制器:
@property (nonatomic, readonly) id sourceViewController; - 目標(biāo)控制器:
@property (nonatomic, readonly) id destinationViewController;
- 唯一標(biāo)識(shí):
-
Segue的類型(可分為兩大類)
-
自動(dòng)型:點(diǎn)擊某個(gè)控件后(比如按鈕),自動(dòng)執(zhí)行Segue,自動(dòng)完成界面跳轉(zhuǎn)
- 按住Control鍵,直接從
控件拖線到目標(biāo)控制器 - 如果點(diǎn)擊某個(gè)控件后,不需要做任何判斷,一定要跳轉(zhuǎn)到下一個(gè)界面,建議使用自動(dòng)Segue;
- 按住Control鍵,直接從
-
手動(dòng)型:需要通過(guò)寫代碼手動(dòng)執(zhí)行Segue,才能完成界面跳轉(zhuǎn)
- 按住Control鍵,從
來(lái)源控制器拖線到目標(biāo)控制器 - 手動(dòng)型的Segue需要設(shè)置一個(gè)標(biāo)識(shí)(Identifier)
- 在恰當(dāng)?shù)臅r(shí)刻,使用perform方法執(zhí)行對(duì)應(yīng)的Segue,完成界面跳轉(zhuǎn)
[self performSegueWithIdentifier:@"login2contacts" sender:nil]; // Segue必須由來(lái)源控制器來(lái)執(zhí)行,也就是說(shuō),這個(gè)perform方法必須由來(lái)源控制器來(lái)調(diào)用- 如果點(diǎn)擊某個(gè)控件后,需要做一些判斷,也就是說(shuō):滿足一定條件后才跳轉(zhuǎn)到下一個(gè)界面,建議使用“手動(dòng)型Segue”
- 按住Control鍵,從
-
-
performSegueWithIdentifier:sender:方法的完整執(zhí)行過(guò)程:- 1.根據(jù)identifier去storyboard中找到對(duì)應(yīng)的Segue線,新建UIStoryboardSegue對(duì)象 - 設(shè)置Segue對(duì)象的sourceViewController(來(lái)源控制器)
- 新建并且設(shè)置Segue對(duì)象的destinationViewController(目標(biāo)控制器)
- 2.調(diào)用sourceViewController(源控制器)的下面方法,做一些跳轉(zhuǎn)前的準(zhǔn)備工作并且傳入創(chuàng)建好的Segue對(duì)象
// 準(zhǔn)備好segue線之后,跳轉(zhuǎn)之前會(huì)調(diào)用 // 做一些數(shù)據(jù)之間的傳值 -(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { // 執(zhí)行跳轉(zhuǎn) CYXContactViewController *vc = segue.destinationViewController; // 傳值 vc.accountStr = _accountField.text; - 1.根據(jù)identifier去storyboard中找到對(duì)應(yīng)的Segue線,新建UIStoryboardSegue對(duì)象 - 設(shè)置Segue對(duì)象的sourceViewController(來(lái)源控制器)
}
```
- 3.調(diào)用Segue對(duì)象的`- (void)perform;`方法開(kāi)始執(zhí)行界面跳轉(zhuǎn)操作
- 如果segue的style是`push`
- 取得`sourceViewController`所在的`UINavigationController`
- 調(diào)用`UINavigationController`的`push`方法將`destinationViewController`壓入棧中,完成跳轉(zhuǎn)
- 如果segue的style是`modal`
- 調(diào)用`sourceViewController`的`presentViewController`方法將`destinationViewController`展示出來(lái)
模型的值發(fā)生改變時(shí)通知控制器(使用Notification通知)<跨控制器傳值也可采取這種方式>
- 在上一個(gè)控制器修改了同一個(gè)模型數(shù)據(jù)
- (IBAction)saveBtnClick:(UIButton *)sender {
//修改模型數(shù)據(jù)
_contact.name = self.nameFiel.text;
_contact.phonenum = self.phoneFiel.text;
//發(fā)出通知
[[NSNotificationCenter defaultCenter]postNotificationName:@"contactChange" object:nil];
[self.navigationController popViewControllerAnimated:YES];
}
- 在下一個(gè)展示模型數(shù)據(jù)的控制器接收通知,刷新視圖
- (void)viewDidLoad {
[super viewDidLoad];
//監(jiān)聽(tīng)模型更新通知
[[NSNotificationCenter defaultCenter]addObserverForName:@"contactChange"
object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *note) {
//此處處理監(jiān)聽(tīng)的事件
//只要監(jiān)聽(tīng)到通知就會(huì)調(diào)用
//這里是更新模型,刷新表格
[self.tableView reloadData];
}];
}