目录
1.属性传值(正向)
2.block传值(反向)
3.通知传值(反向)
4.协议传值(反向)
5.单例传值
1.属性传值(正向)
这样就是正向的属性传值
2.block传值(反向)
思路:
1.首先,创建两个视图控制器,在第一个视图控制器中创建一个UILabel和一个UIButton,其中UILabel是为了显示第二个视图控制器传过来的字符串,UIButton是为了push到第二个界面
2.第二个界面的只有一个UITextField,是为了输入文字,当输入文字,并且返回第一个界面的时候,当第二个视图将要消失的时候,就将第二个界面上TextFiled中的文字传给第一个界面,并且显示在UILabel上
Demo:
效果:
补充:block相关知识点
http://www.jianshu.com/p/f4fa7aeb2035
http://www.jianshu.com/p/2aad46e3ea95
1.使用block时什么情况会发生引用循环,如何解决?
一个对象中强引用了block,在block中又强引用了该对象,就会发射循环引用。
解决方法是将该对象使用__weak或者__block修饰符修饰之后再在block中使用。
id weak weakSelf = self; 或者 weak __typeof(&*self)weakSelf = self该方法可以设置宏
id __block weakSelf = self;
或者将其中一方强制制空 xxx = nil。
检测代码中是否存在循环引用问题,可使用 Facebook 开源的一个检测工具 FBRetainCycleDetector
block使用注意点:
3.通知传值(反向)
Demo1:
效果:
Demo2:(带数据)
VC1:
1.发送通知(传一个数据模型)
OrderListModel *nextModel = [self getNeedModel];//获取下一个要接的乘客
OrderViewModel *orderViewModel = [[OrderViewModel alloc] initWithOrderModel:nextModel];
//通知订单面板刷新
[[NSNotificationCenter defaultCenter] postNotificationName:@"GaodeNaviUpdateMapNaviPopupView" object:nil userInfo:@{@"orderViewModel":orderViewModel}];
VC2:
1.接收通知
- (void)viewDidLoad {
[super viewDidLoad];
//导航中更换终点导航刷新订单面板
[[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(gaodeNaviUpdateMapNaviPopupView:) name:@"GaodeNaviUpdateMapNaviPopupView" object:nil];
}
2.通知回调方法
//通知回调方法-高德导航中改变终点刷新订单面板
- (void)gaodeNaviUpdateMapNaviPopupView:(NSNotification *)sender {
NSDictionary *dic = sender.userInfo;
OrderViewModel *orderViewModel = dic[@"orderViewModel"];
[orderViewModel refreshPrice];
self.mapNavigationPopupView.orderViewModel = orderViewModel;//更新数据
}
3.移除通知
- (void)dealloc {
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
VC1:
1.发送通知(传一个数据)
[[NSNotificationCenter defaultCenter]postNotificationName:@"BBXListMapMergeNotification" object:nil userInfo:@{@"index":[NSString stringWithFormat:@"%ld",(long)i]}];
VC2:
1.接收通知
//任务列表-接送地图标题按钮点击的通知回调
[[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(BBXListMapMergeNotificationAction:) name:@"BBXListMapMergeNotification" object:nil];
2.通知回调方法
//任务列表-接送地图标题按钮点击的通知回调
- (void)BBXListMapMergeNotificationAction:(NSNotification *)sender {
NSDictionary *dic = sender.userInfo;
NSString *index = dic[@"index"];
if ([index isEqualToString:@"1"]) {
self.currentTag = -1;
[self refreshEvent:NO];//网络请求,刷新界面
self.tipsLabel.hidden = YES;
NSArray *tempArray = [NSArray arrayWithArray:self.orderArray];
for (OrderListModel *orderModel in tempArray) {
//有系统空单,移除系统空单数据,显示系统空单提示
if (orderModel.order_origin.intValue == 999) {
self.tipsLabel.hidden = NO;
self.isHaveEmptyOrder = YES;
}
}
}
}
//其他
//各界面弹框点详情到任务列表通知回调
- (void)BBXListMapMergeNotificationSwitchAction:(NSNotification *)sender {
NSDictionary *dic = sender.userInfo;
NSString *index = dic[@"index"];
if ([index isEqualToString:@"0"]) {
NSArray *vcs = [_titleScrollView subviews];
for (id view in vcs) {
if ([view isKindOfClass:[UIButton class]]) {
UIButton *btn = view;
if (btn.tag == index.intValue) {
[self titleClick:btn];
}
}
}
}
}
3.移除通知
- (void)dealloc {
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
Demo3:(通知的其他快捷写法 - 可当前VC发通知再收通知)
补充:通知相关知识点
NSNotification:
这个类可以理解为一个消息对象,其中有三个成员变量;observer是观察者(一般在控制器中是self),它监测通知中心是否有消息发送的那个对象
- name:这个成员变量是这个消息对象的唯一标识,用于辨别消息对象,必须与需要发送通知的名字一致,否则通知无法到达
- object:这个成员变量定义一个对象,可以理解为针对某一个对象的消息;是通知关联的对象,即谁发送的通知(看情况,有时传的值很多,可以通过模型过渡...);也就是监听哪个对象发出的通知,如果使用"nil"值,代表监听所有通知
- userInfo:这个成员变量是一个字典,可以用其来进行传值;也就是传递的附加信息(通知的内容)
NSNotificationCenter:
通信的特点是:为单例模式,可以实现一对多通信,每个应用程序都会有一个默认的通知中心;通知是观察者(observer)模式的一种,结构为:发布者->通知中心->接受者;
基本的使用过程:首先在需要接受数据的对象(或者控制器)注册通知,在需要发布通信的对象中上传通知
移除通知方法:
- 移除通知需要注意的坑:
了解:在了解控制器的生命周期之后,我们都知道viewWillAppear:方法是在控制器的view将要显示的时候调用的,而viewWillDisappear:方法是在控制器的view将要隐藏的时候调用。很多时候我们根据自身需要将相关代码逻辑添加到这两个方法中。
- 小结:
1、iOS7新增加了导航控制器侧滑手势,当触发侧滑返回时,会调用系统的viewWillDisappear:方法,取消侧滑返回时又会调用viewWillAppear:方法。
2、在做手势和通知等一系列操作之时要分情况考虑:若通知和手势是与UI相关的,如监听UITextField键盘的显示和隐藏通知等应该在viewWillAppear:方法中添加通知,在viewWillDisappear:方法中移除通知;而与UI无关的通知和手势,像自定义通知等,应该在viewDidLoad等一次性方法中添加,在dealloc方法中释放。
3、在viewWillAppear:、viewWillDisappear:、viewDidAppear:、viewDidDisappear:等类似于这种会多次调用的系统方法中添加代码时,一定要多考虑业务逻辑,以免出现不必要的麻烦。
注意点:
1.接受者和发布者的通知名字必须一致
2.接受者的对象中注册使用完后应该移除通知,一般在dealloc中移除
3.通知可以用于传值,也可以用于其他地方;通知比较优雅,耦合性低
4.协议传值(反向)
Demo:
效果:
5.单例传值
Demo:
单例类:
.h文件
#import <Foundation/Foundation.h>
@interface Datahandle : NSObject
@property (nonatomic, strong) NSString *passVolud;
+(instancetype)sharedHandle;// 单例方法
@end
.m文件
#import "Datahandle.h"
@implementation Datahandle
// 1.重写init初始化方法(使用抛出异常的方式不让调用)
-(instancetype)init {
@throw [NSException exceptionWithName:@"Datahandle" reason:@"不允许使用" userInfo:nil];
return self;
}
// 2.废弃了系统的init方法,所以自己写一个私有的init方法(重新实现初始化)
-(instancetype)initPrivate {
if (self = [super init]) {
}
return self;
}
// 3.单例实现方法(系统线程加锁方式)
+(instancetype)sharedHandle {
static Datahandle *datahandle = nil;// 用static修饰,这个方法只走一次
@synchronized (self) {// 同步保护(互斥锁,保证线程安全)
if (!datahandle) {
datahandle = [[Datahandle alloc]initPrivate];// 用重新写的私有初始化
}
}
return datahandle;
}
// 方法二(传统创建方式)
//+(instancetype)sharedHandle{
//
// static Datahandle *datahandle = nil;
//
// if (!datahandle){
//
// datahandle = [[Datahandle alloc] init];
// }
// return datahandle;
//}
// 方法三 (线程方式--最优)
//+(instancetype)sharedHandle {
//
// static Datahandle *datahandle = nil;
// static dispatch_once_t onceToken; //给单例加了一个线程锁
//
// dispatch_once(&onceToken, ^{
//
// datahandle = [[Datahandle alloc] init];
// });
// return datahandle;
//}
@end
效果:
单例相关知识点
1.简介
就是一个实例,单例是全局都可以使用的唯一的一个类,相当于一个全局变量,它提供了对类的对象所提供的资源的全局访问点。因此需要用一种只允许生成对象类的唯一实例的机制;
作用:可以保证的程序运行过程,一个类只有一个示例,而且该实例易于供外界访问,从而方便地控制了实例个数,并节约系统资源(就是不论在哪里需要用到这个类的实例变量,都可以通过单例方法来取得,而且一旦你创建了一个单例类,不论你在多少个界面中初始化调用了这个单例方法取得对象,它们所有的对象都是指向的同一块内存存储空间(即单例类保证了该类的实力对象是唯一存在的一个))
2.单例实现思路
• 首先必须创建一个全局实例,通常存放在一个全局变量中,此全局变量设置为nil
• 提供工厂方法对该全局实例进行访问,检查该变量是否为nil,如果nil就创建一个新的实例,最后返回全局实例
• 全局变量的初始化在第一次调用工厂方法时会在+allocWithZone:中进行,所以需要重写该方法,防止通过标准的alloc方式创建新的实例
• 为了防止通过copy方法得到新的实例,需要实现-copyWithZone方法
• 只需在此方法中返回本身对象即可,引用计数也不需要进行改变,因为单例模式下的对象是不允许销毁的,所以也就不用保留
• 因为全局实例不允许释放,所以retain,release,autorelease方法均需重写
注意:类只能有一个实例,并且必须从一个为人数值的访问点对其访问;这个唯一的实例只能通过子类化进行拓展,并且拓展的对象不会破坏客户端代码
3.常见的系统单例
UIApplication(应用程序实例)
NSNotificationCenter(通知)
NSFileManager(文件管理):
NSUserDefaults(应用程序设置):
UIScreen
NSApplication
NSFontManager
NSDocumentController
NSHelpManager
NSNull
NSProcessInfo
NSScriptExecutionContext
4.使用场景
单例模式应用的场景一般发现在以下条件下:
1)资源共享的情况下,避免由于资源操作时导致的性能或损耗等。如上述中的日志文件,应用配置。
2)控制资源的情况下,方便资源之间的互相通信。如线程池等。
简单说就是:整个程序共用一份资源时(我们只需要对这份资源初始化一次)可以使用单例;例如:
1.设置单例类访问应用的配置信息
2.用户的个人信息登陆后用nsuserdefaults 存储,对登录类进一步采用单例封装方便全局访问
3.封装一个单例对应用多处对同一本地数据库进行操作
参考文章:http://blog.csdn.net/blueboyhi/article/details/51074372