跨界面傳值
從一個界面將一個結果值傳到另一個界面,這個是我們在開發過程中非常常見的一個問題。傳值本身並不是一個太復雜的問題,在此主要簡述一下常用的傳值方法。
我們傳值常用的方法主要有四種:
- 1.屬性傳值
- 2.代理傳值
- 3.block傳值
- 4.通知傳值
- 5.KVO
- 對象傳值
屬性傳值:
屬性傳值應該來說是比較簡單的一種傳值方式,但是這種傳值方式有其局限性,常用的一種場合是我們從界面A跳轉到界面B,如何我們想講界面A的值傳到界面B,屬性傳值是比較方便的一種方式。如下圖所示,如果我們點擊A界面上的一個按鈕,跳轉到B界面,並且把A界面的一個值傳送到B界面。
先說明一下大致的原理,首先要創建兩個控制器A和B,在A中導入B的頭文件,在A的按鈕點擊事件中,添加A跳轉到B的代碼段。現在的問題是如何在跳轉的過程中把A界面上的值傳到B界面呢?
我們可以給B添加一個屬性,在點擊按鈕從A跳轉到B的時候,將A界面要傳送的值賦給B的屬性,這樣在B界面可以使用(self.屬性)直接獲取從A界面傳過來的值。
代碼段如下:(下面的代碼段是一個最簡單的演示)

1 #import <UIKit/UIKit.h> 2 3 @interface ViewController : UIViewController 4 { 5 NSString *send;//我們在界面跳轉的時候,將send的值傳到下一個界面 6 } 7 - (IBAction)changeScreenButtonClick:(UIButton *)sender; 8 @end

1 #import "ViewController.h" 2 #import "BViewController.h" 3 @interface ViewController () 4 5 @end 6 7 @implementation ViewController 8 9 - (void)viewDidLoad 10 { 11 [super viewDidLoad]; 12 // Do any additional setup after loading the view, typically from a nib. 13 send = @"傳值操作"; 14 } 15 16 - (void)didReceiveMemoryWarning 17 { 18 [super didReceiveMemoryWarning]; 19 // Dispose of any resources that can be recreated. 20 } 21 22 - (IBAction)changeScreenButtonClick:(UIButton *)sender 23 { 24 BViewController *b = [[BViewController alloc]init]; 25 b.receiveValue = send; 26 UIWindow *window = [UIApplication sharedApplication].delegate.window; 27 window.rootViewController = b; 28 } 29 @end

1 #import <UIKit/UIKit.h> 2 3 @interface BViewController : UIViewController 4 @property(nonatomic,copy) NSString *receiveValue;//接收A界面傳過來的值 5 @end

1 #import "BViewController.h" 2 3 @interface BViewController () 4 5 @end 6 7 @implementation BViewController 8 9 - (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil 10 { 11 self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]; 12 if (self) { 13 // Custom initialization 14 } 15 return self; 16 } 17 18 - (void)viewDidLoad 19 { 20 [super viewDidLoad]; 21 // Do any additional setup after loading the view from its nib. 22 NSLog(@"從A界面傳過來的值為:%@",self.receiveValue); 23 } 24 25 - (void)didReceiveMemoryWarning 26 { 27 [super didReceiveMemoryWarning]; 28 // Dispose of any resources that can be recreated. 29 } 30 31 @end
代理傳值:
代理傳值對應初學者來說有一點難度,但是多使用幾次就好了,像在系統中我們代理這種設計使用的非常廣泛,在此主要說明使用代理傳值的方法。我們在頁面跳轉的過程中,將借助於導航,使用push從A界面跳轉到B界面,使用pop從B界面返回到A界面。
現在我們假設一種場景,我們需要從界面A傳值到界面B,同時也要從界面B傳值到界面A,如何使用代理來實現呢?
首先使用代理傳值,我們需要知道怎么自定義代理,首先先普及一下代理的相關知識。
假如我們需要在A界面傳值到B界面,我們需要在A界面中定義一些協議方法,只需要聲明方法即可,不需要實現,如果其他類想要訪問這些協議方法,只需要遵守這些協議即可。在A中定義的協議方法,相當於一個接口,你想使用A的接口,就要遵守A的協議方法,例如在B中,想要訪問A的協議方法,B就要遵守A的協議。傳值的話,B從A的協議方法中就能獲取到A界面中的值。
如何自己寫一個協議,下面是基本的格式:
1 @protocol 協議名稱 <NSObject> 2 //協議方法 3 @end
假設我們現在要在A界面中寫一個協議,具體代碼如下(傳值是從界面A傳到界面B):

1 #import <UIKit/UIKit.h> 2 3 //協議 4 @protocol aScreenDelegate <NSObject> 5 -(void)sendValueFromScreenaTOScreenb:(NSString *)value; 6 @end 7 8 @interface ViewController : UIViewController 9 @property(nonatomic,assign)id<aScreenDelegate>delegate; 10 - (IBAction)changeScreenButtonClick:(UIButton *)sender; 11 @end

1 #import "ViewController.h" 2 #import "BViewController.h" 3 @interface ViewController () 4 5 @end 6 7 @implementation ViewController 8 9 - (void)viewDidLoad 10 { 11 [super viewDidLoad]; 12 // Do any additional setup after loading the view, typically from a nib. 13 } 14 15 - (void)didReceiveMemoryWarning 16 { 17 [super didReceiveMemoryWarning]; 18 // Dispose of any resources that can be recreated. 19 } 20 21 - (IBAction)changeScreenButtonClick:(UIButton *)sender 22 { 23 BViewController *b = [[BViewController alloc]init]; 24 NSString *send = @"wyg"; 25 self.delegate = b; 26 [_delegate sendValueFromScreenaTOScreenb:send]; 27 [self.navigationController pushViewController:b animated:YES]; 28 } 29 @end

1 #import <UIKit/UIKit.h> 2 #import "ViewController.h" 3 @interface BViewController : UIViewController<aScreenDelegate> 4 @end

1 @implementation BViewController 2 3 - (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil 4 { 5 self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]; 6 if (self) { 7 // Custom initialization 8 } 9 return self; 10 } 11 -(void)sendValueFromScreenaTOScreenb:(NSString *)value 12 { 13 NSLog(@"從A界面傳過來的值:%@",value); 14 } 15 - (void)viewDidLoad 16 { 17 [super viewDidLoad]; 18 // Do any additional setup after loading the view from its nib. 19 20 }
假如你向從界面B,pop到界面A,並把界面B的值傳到界面A,這種使用屬性傳值不太方便,使用代理可以解決,從B界面往A傳值,協議方法應該在B中寫明,在A中遵守協議,下面是具體代碼:

1 #import <UIKit/UIKit.h> 2 #import "BViewController.h" 3 @interface ViewController : UIViewController<bScreenDelegate> 4 - (IBAction)changeScreenButtonClick:(UIButton *)sender; 5 @end

1 #import "ViewController.h" 2 3 @interface ViewController () 4 5 @end 6 7 @implementation ViewController 8 9 - (void)viewDidLoad 10 { 11 [super viewDidLoad]; 12 // Do any additional setup after loading the view, typically from a nib. 13 } 14 //代理方法 15 -(void)sendValueFromBtoA:(NSString *)str 16 { 17 NSLog(@"從B界面傳過來的值為:%@",str); 18 } 19 - (IBAction)changeScreenButtonClick:(UIButton *)sender 20 { 21 BViewController *b = [[BViewController alloc]init]; 22 b.delegate = self; 23 [self.navigationController pushViewController:b animated:YES]; 24 } 25 @end

1 #import <UIKit/UIKit.h> 2 3 @protocol bScreenDelegate <NSObject> 4 -(void)sendValueFromBtoA:(NSString *)str; 5 @end 6 7 @interface BViewController : UIViewController 8 @property(nonatomic,assign) id<bScreenDelegate>delegate; 9 - (IBAction)popButtonClick:(UIButton *)sender; 10 @end

1 #import "BViewController.h" 2 3 @interface BViewController () 4 5 @end 6 7 @implementation BViewController 8 9 - (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil 10 { 11 self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]; 12 if (self) { 13 // Custom initialization 14 } 15 return self; 16 } 17 18 - (void)viewDidLoad 19 { 20 [super viewDidLoad]; 21 // Do any additional setup after loading the view from its nib. 22 23 } 24 - (IBAction)popButtonClick:(UIButton *)sender 25 { 26 NSString *str = @"wxy"; 27 [_delegate sendValueFromBtoA:str]; 28 [self.navigationController popViewControllerAnimated:YES]; 29 } 30 @end
block傳值
使用block傳值,我們需要自定義代理,這種寫法相對來說是比較麻煩的,使用block傳值的話,會使得代碼量大大縮減,現在我們假設我們要把界面A上的值傳到界面B,使用block來實現。
現在假設我們想在界面A上直接獲取界面B上的信息,如何獲取,代碼如下:

1 #import <UIKit/UIKit.h> 2 #import "BViewController.h" 3 @interface ViewController : UIViewController 4 @end

1 #import "ViewController.h" 2 #import "BViewController.h" 3 @interface ViewController () 4 5 @end 6 @implementation ViewController 7 8 - (void)viewDidLoad 9 { 10 [super viewDidLoad]; 11 // Do any additional setup after loading the view, typically from a nib. 12 BViewController *b = [[BViewController alloc]init]; 13 [b converyValueToA:^(NSString *str) { 14 NSLog(@"B界面上的值為:%@",str); 15 }]; 16 } 17 @end

1 #import <UIKit/UIKit.h> 2 @interface BViewController : UIViewController 3 -(void)converyValueToA:(void(^)(NSString *))block; 4 @end

1 #import "BViewController.h" 2 3 @interface BViewController () 4 5 @end 6 7 @implementation BViewController 8 9 - (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil 10 { 11 self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]; 12 if (self) { 13 // Custom initialization 14 } 15 return self; 16 } 17 -(void)converyValueToA:(void (^)(NSString *))block 18 { 19 NSString *name = @"wxy"; 20 block(name); 21 } 22 - (void)viewDidLoad 23 { 24 [super viewDidLoad]; 25 // Do any additional setup after loading the view from its nib. 26 27 } 28 29 @end
通知傳值
通知傳值有點類似於廣播,有發送者,有監聽者,比如A想接受B的值,B要發送一個通知,A只要監聽這個通知,就能接收到值,通知傳值就不細述。
例如發送一個通知:
NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
[center postNotificationName:通知名字 object:self userInfo:傳遞參數];
接收一個通知:
NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
[center addObserver:self selector:@selector(receiveNofitication:) name:通知名字 object:nil];
-(void)receiveNofitication:(NSNotification *)notification
{//接收到通知,執行相關代碼}
跨應用傳值


1 - (IBAction)toPayApp:(id)sender 2 { 3 //設置跳轉到應用程序的鏈接 4 //雙斜杠之后是傳遞的參數,多個參數使用&連接 5 NSURL *url = [NSURL URLWithString:@"payApp://name=iPhone6&price=5288"]; 6 //跳轉前先判斷,是否可以打開鏈接 7 if ([[UIApplication sharedApplication] canOpenURL:url] == YES) 8 { 9 [[UIApplication sharedApplication] openURL:url]; 10 } 11 else 12 { 13 NSLog(@"連接不能打開,應用程序未安裝"); 14 } 15 }
現在我們已經進入到PayApp,如何在這個應用中接受傳過來的參數呢?
我們可以在AppDelegate這個.m文件中添加下面的方法:
1 - (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation