一、属性传值
对于属性传值而言,相对于其它的三种 方法来说,是最基础,最简单的一种 方法,但,属性传值 有很大的局限性,因为是适用于第一个界面向第二个界面传 值,第二个向第三个界面传值等等。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一样,一旦创建,将不能被系统进行回收,所以 这块内存区域会一直存在,直到程序退出,如果大量采用单例的话,会造成大量的内存空间浪费。可以 使用,但不能大量的使用。