一、屬性傳值 對於屬性傳值而言,相對於其它的三種 方法來說,是最基礎,最簡單的一種 方法,但,屬性傳值 有很大的局限性,因為是適用於第一個界面向第二個界面傳 值,第二個向第三個界面傳值等等。N界面向N + 1界面傳值。而在此基礎上,必須知道跳轉界面的明確位置及所要傳的值的具體類型。在第二個界面中聲明
一、屬性傳值
對於屬性傳值而言,相對於其它的三種 方法來說,是最基礎,最簡單的一種 方法,但,屬性傳值 有很大的局限性,因為是適用於第一個界面向第二個界面傳 值,第二個向第三個界面傳值等等。N界面向N + 1界面傳值。而在此基礎上,必須知道跳轉界面的明確位置及所要傳的值的具體類型。在第二個界面中聲明所要傳值 類型的屬性。
@interface SecondViewController : UIViewController //聲明一個字元串屬性來保存第一個界面傳過來的字元串內容 @property (nonatomic, copy)NSString *string; @property (nonatomic, copy)UIColor *color; @property (nonatomic, retain)UILabel *label;
當然,在第二個界面中使用所聲明的屬性
- (void)viewDidLoad { [super viewDidLoad]; self.view.backgroundColor = _color; UIButton *button = [UIButton buttonWithType:UIButtonTypeSystem]; button.frame = CGRectMake(100, 200, 200, 50); [button setTitle:self.string forState:UIControlStateNormal];
在屬性傳值 的時候,需要知道明確跳轉的位置及所要傳的值的類型。
@implementation FirstViewController - (void)right{ SecondViewController *secondVC = [[SecondViewController alloc] init]; secondVC.string = self.textField.text; secondVC.color = self.view.backgroundColor; [self.navigationController pushViewController:secondVC animated:YES]; }
二、協議傳值
通常,協議傳值可以和屬性傳值一起使用,屬性傳值是從前往後依次傳值,而協議 是從後往前來傳值。
協議傳值可以簡單的分為六步來實現。
1.聲明協議 2.聲明代理 3.執行協議方法 4.接收協議 5.設置協議 代理對象 6.實現協議方法
//1.聲明協議 @protocol FourViewControllerDelegate <NSObject> - (void)change:(NSString *)string; - (void)changeColor:(UIColor *)color; @end @interface FourViewController : UIViewController @property (nonatomic, retain)UITextField *textField; //2.聲明代理 @property (nonatomic, assign)id<FourViewControllerDelegate>fouDelegate; @end
@implementation FourViewController - (void)back{ //3.執行協議方法 if (self.fouDelegate != nil && [self.fouDelegate respondsToSelector:@selector(change:)]) { [self.fouDelegate change:self.textField.text]; [self.fouDelegate changeColor:self.view.backgroundColor]; } [self.navigationController popViewControllerAnimated:YES]; }
而如果想要使用協議,而必須要接收協議
//5.接收協議 @interface ThreeViewController : UIViewController<FourViewControllerDelegate> @property (nonatomic, retain)UILabel *label; @end
1 @implementation ThreeViewController 2 3 //6.實現協議方法 4 - (void)change:(NSString *)string{ 5 self.label.text = string; 6 } 7 - (void)changeColor:(UIColor *)color{ 8 self.view.backgroundColor = color; 9 } 10 -(void)button{ 11 FourViewController *fourVC = [[FourViewController alloc] init]; 12 //4.指定第二個界面的代理對象為第一個視圖控制器 13 fourVC.fouDelegate = self; 14 [self.navigationController pushViewController:fourVC animated:YES]; 15 }
三、block傳值
相比於前兩種來說,應該知道,block是匿名函數。既然是函數,也就會有那四種 表現形式,無參無返回值,有參無返回值,有參無返回值,有參有返回值這四種 形式。所以 block相對於前兩種來說,表現方式 多樣。
1 __block int a = 0; 2 void (^block1)(void) = ^(void){ 3 a ++; 4 NSLog(@"%d",a); 5 }; 6 block1(); 7 8 void (^block2)(int age, NSString *string) = ^(int age, NSString *string){ 9 NSLog(@"age is %d, text is %@", age, string); 10 }; 11 block2(20, @"xiaoming");
12 NSString *(^block3)(void) = ^(void){ 13 return @"有參wu返回值"; 14 }; 15 NSLog(@"block3 is %@", block3()); 16 NSString *(^block4)(NSString *text) = ^(NSString *string){ 17 return [string stringByAppendingString:@"有返回值"]; 18 }; 19 NSLog(@"block4 is %@",block4(@"有參有返回值"));
block和協議傳值的作用類似,但不同於協議傳值的繁瑣,block有很好的操作性。
在第二個界面聲明block
#import <UIKit/UIKit.h> typedef void (^BaDaBlock)(NSString *); typedef void (^colorBlock)(UIColor *); @interface SecondViewController : UIViewController @property (nonatomic, retain)UITextField *textField; @property (nonatomic, copy)BaDaBlock bada; @property (nonatomic, copy)colorBlock cBlock; @end
Block聲明成屬性,一定要用copy
因為Block存儲的內容在棧區,用copy複製一份到堆區,不能用retain的原因是,retain只能使堆區中的引用計數加1,而不能使棧區的引用計數加1
在第二個界面執行所聲明的blcok方法
@implementation SecondViewController - (void)back{ //執行Block if (self.bada != nil ) { self.bada(self.textField.text); } if (self.cBlock != nil) { self.cBlock(self.view.backgroundColor); } [self.navigationController popViewControllerAnimated:YES]; }
Block專門釋放的方法 Block_release(_bada);
Block_release(_cBlock);
使用在第一個界面使用block
@implementation FirstViewController - (void)button{ SecondViewController *secondVC = [[SecondViewController alloc] init]; secondVC.bada = ^(NSString *str){ self.label.text = str; }; secondVC.cBlock = ^(UIColor *color){ self.view.backgroundColor = color; }; [self.navigationController pushViewController:secondVC animated:YES]; [secondVC release]; }
四、單例傳值
單例,簡單的來說,就是單個的實例對象,不管被創建多少次,都具有唯一性,只有惟一的一個。
單例的使用範圍不限定,但需要知道明確跳轉的位置,和所需傳值 的類型。
而單例 ,系統內部也有定義,像UIScreen, UIDevice都是系統內部定義 的單例,而通常使用的則是用戶自定義的單例
#import <Foundation/Foundation.h> @interface Handler : NSObject @property (nonatomic, copy)NSString *string; //單例方法是類方法,返回值類型為instancetype //自己定義的單例類,方法名通常都以share開頭 +(instancetype)shareInstance; @end
實現所聲明的單例方法
#import "Handler.h" static Handler *handler = nil; @implementation Handler +(instancetype)shareInstance{ //加鎖,保證創建過程在同一時間內只能允許一個線程對象訪問 @synchronized(self){ if (nil == handler) { handler = [[Handler alloc]init]; } } return handler; } @end
在實現的聲明的單例方法時,一定要確保所創建的單例是唯一的。
在實現跳轉的地方創建單例,將值賦給單例類聲明的屬性。
- (void)getAction{ TwoViewController *twoVC = [[TwoViewController alloc] init]; //創建單例 Handler *handler = [Handler shareInstance]; handler.string = _textField.text; [self.navigationController pushViewController:twoVC animated:YES]; }
使用傳過來的單例值
@implementation ThreeViewController - (void)viewDidLoad { [super viewDidLoad]; Handler *handler = [Handler shareInstance]; UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(100, 100, 200, 50)]; label.text = handler.string;
註意:
因為單例可以全局使用,非常方便,並且唯一性。那怎麼不大量使用呢?當然不能大量使用,因為是全局可以使用,相當於static一樣,一旦創建,將不能被系統進行回收,所以 這塊記憶體區域會一直存在,直到程式退出,如果大量採用單例的話,會造成大量的記憶體空間浪費。可以 使用,但不能大量的使用。