標籤:
iOS頁面傳值方式
應用於:
- 兩個互動的介面:1)頁面一跳轉到頁面二,頁面一的textField的值傳給頁面二的label。2)A頁面跳轉到B頁面,B頁面再跳回A頁面(註冊頁面跟登入頁面)
- 兩個不互動的兩個介面:資料持久層跟展示層的資料互動。
幾種傳值方式:
- 屬性傳值
- 委託delegate方式
- 通知notification方式
- block方式
- 單例模式方式
- UserDefault或者檔案方式
1.屬性傳值(順傳):
- 需要定義一個公開的屬性
- 需要一個你需要傳值的對象
- 進行屬性賦值
實現:A、B兩個介面,通過按鈕將A介面textField的值傳給頁面B的label。
A:ViewController B:DetailViewController
#import "ViewController.h" @interface ViewController () @property (nonatomic, strong) UITextField *textField; @end @implementation ViewController-(void)buttonAction:(UIButton *)button{DetailViewController *detailViewController = [[DetailViewController alloc]init];//用下一個視圖的屬性接受想要傳過去的值,屬性傳值detailViewController.firstValue = self.txtFiled.text;[self.navigationController pushViewController:second animated:YES];}DetailViewController介面#import "DetailViewController.h" @interface DetailViewController () @property (nonatomic, weak) NSString firstValue;//接收textField傳過來的值。 @end
2.代理傳值(順傳倒傳都可以)
delegate只能是一對一之間的。他只能是navigation的棧裡面的相鄰控制器傳值, 不能跨控制器傳值。比如:a到b,b到c.,而不能從c傳到a.
- 擬定?份協議(命名一般是XXXDelegate),協議裡面的?法的參數取決於你要傳遞的內容
- 設定代理人屬性(再次強調,使用assign防?循環參考)
- 在需要調?的地?調?,這?步比較抽象,?如上面所講例?子,我們是需要在button點擊的時候
- 傳值並且取消介面,所以我們的delegate就在這個?面的進?調用
- 讓相應的對象成為代理人,?般都是在建立的時候指定一個代理?
- 遵守協議,並且實現相應的方法,然後在方法中進行邏輯處理
實現:A頁面push到B頁面,如果 B頁面的資訊想回傳(回調)到A頁面,用代理傳值,其中B定義協議和聲明代理,A確認並實現代理,A作為B的代理
A頁面:RootViewControllers B頁面:DetailViewControllers
ViewControllers.h檔案#import <UIKit/Uikit.h>@class DetailViewController;@protocol PassingValueDelegate<NSObject>//擬定協議@optional-(void)passValues:(NSString *)values;//定義協議方法(values你想要傳遞的內容)@end@interface ViewControllers: UIViewController@property (nonatomic, weak)id< PassingValueDelegate > delegate; (valueDelegate)//設定代理屬性,通過其傳值(為防止循環參考,此處採用了weak或者assign)點擊按鈕事件函數(調用代理)-(void)trendBtnClick{ //create the view DetailViewController * detailViewController = [[DetailViewController alloc] initWithNibName:@" DetailViewController " bundle:nil]; //傳值並且取消介面 self.delegate (自己命名的valueDelegate )= detailViewController; //設定代理 ,讓相應的對象成為代理人 [self.trendDelegate passValues:@"123456"]; //頁面跳轉 }DetailViewController.h 檔案引用ViewController的標頭檔,並添加代理協議如下#import "ViewController.h" @interface TrendViewController : UIViewController<PassTrendValueDelegate>{ } @end實現代理函數:#pragma mark 實現傳值協議方法 -(void)passValues:(NSString *)values{ NSLog(@"values=%@",values); }
最重要也是最容易忽略的,就是一定要設定delegate的指向
3.通知傳值(順傳倒傳都可以)第三個頁面的值傳給第一個頁面
誰要監聽值的變化,誰就註冊通知 ,特別要注意,通知的接受者必須存在這一先決條件不用通知的時候,記得移除。
- 在第三個介面中, 建?一個通知中樞, 通過通知中樞, 發送通知(發送通知的過程就是傳值的過程,將要傳輸的值作為object的值傳給第一個介面
- 在第?個介面建?一個通知中樞, 通過通知中?,註冊一個監聽事件
- 在第一個界?中,設定接收到通知的事件。
- 在第?個界?面中的dealloc中, 將通知中樞remove掉
任何對象對可以發送通知到中心,同時任何對象可以監聽中心的通知。
發送通知的代碼如下:
[[NSNotificationCenter defaultCenter] postNotificationName:@”myNotificationName” object:broadcasterObject];
註冊接收通知的代碼如下:
[[NSNotificationCenter defaultCenter] addObserver:listenerObject selector:@selector(receivingMethodOnListener:) name:@”myNotificationName” object:nil];
實現:將B介面的值傳給A介面,所以B介面發送通知到通知中樞,A介面註冊成為監聽者,監聽B值的變化,接受從通知中樞回傳的B的值。如果c頁面也想接受B的值,也同樣註冊成為監聽者就行。(所以可以實現多對多)
A介面:RootViewController B介面:SecondViewController
在B介面建立通知中樞,將要傳的值nameTextField.text通過通知中樞發送
//SecondViewController.m-(IBAction)notificationMethod:(id)sender {[[NSNotificationCenter defaultCenter] postNotificationName:@‘ChangeNameNotification‘ object:self userInfo:@{@‘name‘:self.nameTextField.text}];[self dismissViewControllerAnimated:YES completion:nil];}在A頁面的控制器中,註冊通知://RootViewController.m- (void)viewDidLoad.{[super viewDidLoad];[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(ChangeNameNotification:) name:@‘ChangeNameNotification‘ object:nil];}調用,顯示//RootViewController.m-(void)ChangeNameNotification:(NSNotification*)notification{NSDictionary *nameDictionary = [notification userInfo];self.nameLabel.text = [nameDictionary objectForKey:@‘name‘];.}當我們不使用時,要記得刪掉通知://RootViewController.m-(void)dealloc{[[NSNotificationCenter defaultCenter] removeObserver:self];}
4. block傳值(順傳倒傳都可以)block同樣用於回調
- 為block取別名。並且在參數列表中將需要傳遞的參數寫形參
- 設定block屬性(注意使用copy)
- 設定一個方法持有當前block
- 在合適的地方進行調用類似代理
- 在建立該對象的地方進行block方面的調用
//block文法
//傳回值類型 (^block參數名) (參數類型 參數名) = ^傳回值類型 (參數類型 參數名)
實現:將B介面的textField.text傳給A介面的Label
A頁面:RootViewControllers B頁面:DetailViewControllers
DetailViewController檔案
#import <UIKit/Uikit.h>typedef void (^DetailBlock)(NSString *);//block取別名。並且在參數列表中將需要傳遞的參數寫形參@interface DetailViewController : UIViewController@property (nonatomic, copy) PassingValueBlock passingvalue;//設定block屬性(注意使用copy)@property (weak, nonatomic) UITextField *inputTF;@end- (IBAction)BtnAction:(id)sender { //判斷block是否為空白 if (self.NextViewControllerBlock) { self.NextViewControllerBlock(self.inputTF.text); } [self.navigationController popViewControllerAnimated:YES];}//點擊按鈕到A介面RootViewController.m@property (strong, nonatomic) UILabel *textLabel; -(void)handleButton: (NSString*)sender{DetailViewController *detailViewController = [[DetailViewController alloc]init];detailViewController.passingValue=^( NSString* str){self. textLabel.text= str;}[self.navigationController pushViewController:detailViewController animated:YES];}
5. 單例傳值(順傳倒傳都可以)
單例的好處就在於只是建立了一次,其餘任何時候訪問到的對象都是同一個,所以很多時候用到使用者的一些資訊都是儲存在單例中的,這樣就不需要多次傳值了,只需要再次建立單例就可以了
AppStatus.h 建立一個單例類 AppStatus
#import <Foundation/Foundation.h>
@interface AppStatus : NSObject
{
NSString *_contextStr;
}
@property(nonatomic,retain)NSString *contextStr;
+(AppStatus *)shareInstance;
@end
AppStatus.m
#import "AppStatus.h"
@implementation AppStatus
@synthesize contextStr = _contextStr;
static AppStatus *_instance = nil;
+(AppStatus *)shareInstance
{
if (_instance == nil)
{
_instance = [[super alloc]init];
}
return _instance;
}
-(id)init
{
if (self = [super init])
{
}
return self;
}
@end
RootViewController.h
#import "RootViewController.h"
#import "DetailViewController.h"
#import "AppStatus.h"
@interface RootViewController ()
@end
@implementation RootViewController
-(void)pushAction:(id)sender
{
tf = (UITextField *)[self.view viewWithTag:1000];
//單例傳值 將要傳遞的資訊存入單例中(共用中)
// [[AppStatus shareInstance]setContextStr:tf.text]; 跟下面這種寫法是等價的
[AppStatus shareInstance].contextStr = tf.text;
//導航push到下一個頁面
DetailViewController *detailViewController = [[DetailViewController alloc]init];
//導航push到下一個頁面
[self.navigationController pushViewController:detailViewController animated:YES];
}
@end
DetailViewController.h
#import <UIKit/UIKit.h>
@protocol ChangeDelegate;//通知編譯器有此代理
@interface DetailViewController : UIViewController
{
UITextField *textField;
}
@end
#import "DetailViewController.h"
#import "AppStatus.h"
@interface DetailViewController ()
@end
@implementation DetailViewController
@synthesize naviTitle = _naviTitle;
-(void)loadView
{
self.view = [[[UIView alloc]initWithFrame:CGRectMake(0, 0, 320, 480)]autorelease];
//單例
self.title = [AppStatus shareInstance].contextStr;
textField = [[UITextField alloc]initWithFrame:CGRectMake(100, 100, 150, 30)];
textField.borderStyle = UITextBorderStyleLine;
[self.view addSubview:textField];
UIBarButtonItem *doneItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDonetarget:self action:@selector(doneAction:)];
self.navigationItem.rightBarButtonItem = doneItem;
[doneItem release];
}
//這個方法是執行多遍的 相當於重新整理view
-(void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
tf = (UITextField *)[self.view viewWithTag:1000];
tf.text = [AppStatus shareInstance].contextStr;
}
//pop回前一個頁面
-(void)doneAction:(id)sender
{
//單例傳值
[AppStatus shareInstance].contextStr = textField.text;
[self.navigationController popToRootViewControllerAnimated:YES];
}
6.NSUserDefault傳值(順傳倒傳都行)
[[NSUSerDefault standardUserDefaults]setObject:要傳的值 forKey:對這個值得標記鍵];//設定值
[[NSUserDefault standardUserDefaults]ObjectForKey:根據你的標記鍵];//擷取值
iOS學習之六種傳值方式