一、目录
- 属性 传值
- 单例 传值
- block传值
- 代理 传值
- 总结
- 个人使用心得
- 代码下载地址:https://github.com/ChenZeBin/SendValue
二、掌握四大传值前提
1.掌握push跳转 相关文章链接:http://www.jianshu.com/p/46f693f761a1
2.掌握单例模式
3.掌握block
4.掌握代理
三、介绍
1、属性传值
(1)、介绍:
比如A视图要给B视图传值字符“abc”
1,B视图就声明一个属性NSSTring来接受字符abc
2,A视图中new一个B控制器,B.NSString = “abc”
3,这样就赋值过去了
(2)、代码:
// B视图的.h文件
@property (nonatomic,copy) NSString *propertySendString;
// 用来接受A视图传递过来的数据
// A视图的.m文件
Delegate *vc = [self.storyboard instantiateViewControllerWithIdentifier:@"delegateVC"];
vc.propertySendString = @"属性传值";
[self.navigationController pushViewController:vc animated:YES];
(3)、注意:
在A视图里面new了B视图,这时候跳转到B视图,一定一定一定要把这个new的视图push过去,不然如果是故事版脱线跳转的话,跳转过来的就不是这个new的B控制器了,那么传递肯定是失败的
2、单例传值
(1)、介绍:
单例就是整个APP只有一个对象,比如我把A类设为单例,那么我new的A类对象都是同一样,不会出现第二个的,这样我给A类中的一个变量赋值,那么我在其他视图想要用的时候,我就只需要new这个单例对象去拿这个变量的值就可以了
(2)、代码
// 创建一个单例类 这个类的.h文件
#import <Foundation/Foundation.h>
@interface SingleTon : NSObject
// 传值的属性
@property (nonatomic,copy) NSString *passValue;
// 创建单例 (单例的命名,shared+类名)
+ (SingleTon *)sharedSingleTom;
@end
// 这个类的.m文件
#import "SingleTon.h"
@implementation SingleTon
// 以下是创建单例的方法,这是严格的单例,所以代码偏多
// 严格是创建单例步骤
static SingleTon *singleTon;
+ (instancetype)allocWithZone:(struct _NSZone *)zone {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
singleTon = [super allocWithZone:zone];
});
return singleTon;
}
+ (SingleTon *)sharedSingleTom {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
singleTon = [[SingleTon alloc] init];
});
return singleTon;
}
-(id)copyWithZone:(NSZone *)zone{
return singleTon;
}
@end
// 比如我A界面想把abc传到B界面,
// 那么我这个单例类就是传值的中间介质
// 以下代码就是给单例的变量赋值(赋我要传的值)
// 比如我在A界面里给单例变量赋值,那么接下来我在B界面里,创建这个单例,然后直接调用这个单例变量,这个变量就是abc的值了
SingleTon *singleTon = [SingleTon sharedSingleTom];
singleTon.passValue = @"单例传值";
3、block传值
(1)、介绍
可以向任何方向传值
比如我A类中有个值要传出来,那么我就在A类写一个类方法,类方法的参数是block,然后这个block的参数是我要传的值
这样我在B类就可以用直接用A类调用这个类方法,然后这个类方法的block回调里就会带一个参数,这个参数是带有值的,值就是从A类block参数带出来的
(2)、代码
// A类的.h文件
#import <Foundation/Foundation.h>
// 定义一个闭包(block),然后参数是字符串
typedef void (^sentValue)(NSString *str);
@interface Block : NSObject
// 定义一个类方法,参数是这个闭包
+ (void)sentValueClick:(sentValue)_sentBlock ;
@end
// A类的.m文件
#import "Block.h"
@implementation Block
// 实现.h文件中定义的类方法
+ (void)sentValueClick:(sentValue)_sentBlock {
// 这个给这个闭包传的参数“block传值”就是你要传的值了
_sentBlock(@"block传值");
}
@end
// 你想在哪里拿到这个值,就在哪里调用这个方法,这个str参数就是传出来的值
[Block sentValueClick:^(NSString *str) {
NSLog(@"block:%@",str);
}];
4、代理传值
(1)、介绍:
代理传值一般用于后向前传值
比如我A点击跳转到B界面,然后想把B界面的值传递到A界面,并且跳转回A界面
那么我就在B界面写一个代理和代理方法,然后再B界面视图消失的方法里面调用这个代理方法,这时候由于你已经设置A界面为B的代理对象了,所以在B界面快消失的时候调用代理方法,其实是A界面调用了代理方法,所以这时候就可以把我要传递的值传递过去(有点难理解,具体看下代码)
(2)、代码
// B界面.h文件
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
@protocol SentValueDelegate <NSObject>
@optional
- (void)sentValueClicked:(NSString *)str;
@end
@interface Delegate : UIViewController
@property (nonatomic,weak) id <SentValueDelegate> delegate;
@property (nonatomic,copy) NSString *propertySendString;
@end
//B界面.m文件
// 视图即将消失会自动调用的方法
- (void)viewWillDisappear:(BOOL)animated {
if ([_delegate respondsToSelector:@selector(sentValueClicked:)]) {
[self.delegate sentValueClicked:@"代理传值"];
}
}
// A界面的.m文件
// 点击按钮跳转到第二个页面 代理传值(后向前传值)
- (IBAction)pushClicked:(UIButton *)sender {
Delegate *delegateVC = [self.storyboard instantiateViewControllerWithIdentifier:@"delegateVC"];
delegateVC.delegate = self;
[self.navigationController pushViewController:delegateVC animated:YES];
}
// 实现代理的方法(这个方法包含着一个参数,这个参数就是从B页面传递过来的值)
- (void)sentValueClicked:(NSString *)str {
NSLog(@"%@",str);
}
(3)、补充说明
对于这个代理,确实有点难理解,这里我说下执行的顺序
首先是A类的.m文件
我点击按钮,跳转到B界面,这时候我点击按钮就会来到按钮的监听方法,在这个方法里面new一个B控制器,然后这时候就要设置B的代理为A类,因为这时候要先设置好,等下B类调用代理方法才会来到这里
// A界面的.m文件
// 点击按钮跳转到第二个页面 代理传值(后向前传值)
- (IBAction)pushClicked:(UIButton *)sender {
Delegate *delegateVC = [self.storyboard instantiateViewControllerWithIdentifier:@"delegateVC"];
delegateVC.delegate = self;
[self.navigationController pushViewController:delegateVC animated:YES];
}
// 实现代理的方法(这个方法包含着一个参数,这个参数就是从B页面传递过来的值)
- (void)sentValueClicked:(NSString *)str {
NSLog(@"%@",str);
}
跳转到B类后,在B类快要消失的方法写以下代码
代码的说明:如果delegate这个代理属性响应了这个方法
if ([_delegate respondsToSelector:@selector(sentValueClicked:)]) {
如果响应了就执行以下代码,那么这里就是关键了
我刚才是A类实现代理方法,就是响应就这个方法
刚才我在A类把delegate = A类控制器
(设置了代理),
所以这时候self.delegate
是等于A类控制器的self
那么以下的代码就相当于[A类的self 调用sentValueClicked]
[self.delegate sentValueClicked:@"代理传值"];
那么这时候,程序就会来到A类实现的代理方法,
看以下代码,这时候,这个方法的参数str就是
[self.delegate sentValueClicked:@"代理传值"];
里面的"代理传值"
// 实现代理的方法(这个方法包含着一个参数,这个参数就是从B页面传递过来的值)
- (void)sentValueClicked:(NSString *)str {
NSLog(@"%@",str);
}
以上就是代理传值理解的关键地方,如果这个可以理解好,那么代理是怎么执行的也就可以理解好了
- (void)viewWillDisappear:(BOOL)animated {
if ([_delegate respondsToSelector:@selector(sentValueClicked:)]) {
[self.delegate sentValueClicked:@"代理传值"];
}
}
四、总结
-
属性 传值 : 前向后
-
单例 传值 : 任何方向
主要思想:单例做为一个中介 -
block传值: 任何方向
主要思想:哪个类要把值传出来,哪个类就写闭包(block),然后自动类方法+闭包参数的方法,把参数传出来 -
单例 传值: 后向前
主要思想:哪个类需要把值传出来,就在哪个类写一个代理,然后想要获取到这个值的话,那么就设置自己为这个类的代理对象,然后去实现它的代理方法,通过这个方法的参数拿到值
五、个人使用心得
最简单的方式:
属性传值,但是局限在前向后,为什么呢?
因为我A类传值给B类,这里最主要的关键实现是,在A类中new一个B类,并且把我要传的值赋值给B类的接受变量,然后把B类的对象push到B界面
,这时候在B类用self.接受变量
就可以拿到值了
其实,这里实现的关键,就是B类的对象
在A类中new B类的对象,进行赋值,在B界面调用self也是这个B类对象,也就是说这是同一个对象,同一块内存空间的,所以,理所当然可以赋值,然后传值过去
所以大概知道为什么只能前向后了把,因为这个实现的关键就是要控制同一个B类对象,如果我是后向前,那么我B类里面,我就得new一个A类对象,但是如果我是用pop
是没办法把A对象传递过去的,也就是说我这时候回到A界面又重新new 了一个A对象,所以传值失败的
最喜欢的方式:
block传值:因为这个block可以向任何地方传值,步骤又少
#######使用最多的方式:
block传值和属性传值,如果是前向后我会用属性传值,其他情况大多是用block
网友评论