RAC冷热信号
概念区别
-
Hot Observable是主动的,尽管你并没有订阅事件,但是它会时刻推送,就像鼠标移动;
而Cold Observable是被动的,只有当你订阅的时候,它才会发布消息。 -
Hot Observable可以有多个订阅者,是一对多,集合可以与订阅者共享信息;
而Cold Observable只能一对一,当有不同的订阅者,消息是重新完整发送。
例子
RACSubject及其子类是热信号,类似“直播”,错过了就不再处理。
RACSignal是冷信号,类似“点播”,每次订阅都会从头开始。
如何将一个冷信号转化成热信号——广播
如果冷信号中包含网络请求,那么每次订阅这个冷信号都会发送网络请求,而且任何的信号转换即是对原有的信号进行订阅从而产生新的信号。
冷信号与热信号的本质区别在于是否保持状态,冷信号的多次订阅是不保持状态的,而热信号的多次订阅可以保持状态。所以一种将冷信号转换为热信号的方法就是,将冷信号订阅,订阅到的每一个时间通过RACSbuject发送出去,其他订阅者只订阅这个RACSubject。
RACSignal *coldSignal = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
NSLog(@"Cold signal be subscribed.");
[[RACScheduler mainThreadScheduler] afterDelay:1.5 schedule:^{
[subscriber sendNext:@"A"];
}];
[[RACScheduler mainThreadScheduler] afterDelay:3 schedule:^{
[subscriber sendNext:@"B"];
}];
[[RACScheduler mainThreadScheduler] afterDelay:5 schedule:^{
[subscriber sendCompleted];
}];
return nil;
}];
RACSubject *subject = [RACSubject subject];
NSLog(@"Subject created.");
RACMulticastConnection *multicastConnection = [coldSignal multicast:subject];
RACSignal *hotSignal = multicastConnection.autoconnect;
[[RACScheduler mainThreadScheduler] afterDelay:2 schedule:^{
[hotSignal subscribeNext:^(id x) {
NSLog(@"Subscribe 1 recieve value:%@.", x);
}];
}];
[[RACScheduler mainThreadScheduler] afterDelay:4 schedule:^{
[hotSignal subscribeNext:^(id x) {
NSLog(@"Subscribe 2 recieve value:%@.", x);
}];
}];
细说ReactiveCocoa的冷信号与热信号(一)
细说ReactiveCocoa的冷信号与热信号(二):为什么要区分冷热信号
细说ReactiveCocoa的冷信号与热信号(三):怎么处理冷信号与热信号
内存泄漏
- RACObserve的定义里面却用到了self,所以,当RACObserve出现在block中要小心
- (void)viewDidLoad
{
[super viewDidLoad];
RACSignal *signal = [RACSignal createSignal:^RACDisposable *(id < RACSubscriber > subscriber) {
GJModel *model = [[GJModel alloc] init];
[subscriber sendNext:model];
[subscriber sendCompleted];
return nil;
}];
@weakify(self); //
self.signal = [signal flattenMap:^RACStream *(GJModel *model) {
@strongify(self); //
return RACObserve(model, title); // 这里有self
}];
[self.signal subscribeNext:^(id x) {
NSLog(@"subscribeNext - %@", x);
}];
}
- 使用RACSubject,如果进行了map操作,那么一定要发送完成信号,不然会内存泄漏。
使用简介
性能
性能监控
美团的案例: 移动端性能监控方案Hertz
离屏渲染
启动时间
设计模式
面向对象三大特性
封装,继承,多态
五大设计原则
- 单一职责
- 开放闭合
- 依赖倒转
- 里氏代换
- 迪米特法则
创建型模式(5种)
这几个模式都是关于类的创建的。
-
工厂方法
简单工厂:例子是加减乘除计算器;基类产品定义接口(两个操作数,一个计算操作);子类产品就是具体的加减乘除具体的计算;工厂对应基类,建造的时候要输入一个字符串指定类型,工厂内有switch
语句判断;
工厂方法就是把switch
语句优化掉,每种具体的计算类都配一个工厂,让客户端决定需要的工厂来创建相应的产品。 -
抽象工厂
例子是更换数据库;产品有多个,比如用户,部门等等;数据库也有多种,比如Sql和Access。
把相关联的产品(用户,部门等)的创建方法接口集合在一起,形成一个系列;具体的工厂(Sql,Access等等)实现这些创建方法;
结合反射技术,更换数据的库的时候,只要更换相应的配置文件就可以了; -
单例
保证一个类只有一个实例,并提供一个全局访问点,一般是getInstance()
方法;iOS
中的dispatch_once
非常适合做这个。 -
原型
实现clone()
接口,通过复制一个对象来创建一个新对象; -
建造者
对象建造需要分为几个部分,这几个部分的顺序基本不变。每个部分的内部具体实现可以变化。可以定义一个建造者,定义各个部分的接口;具体的建造者实现这些部分的接口;再定义一个指挥者,定义一个建造方法,规定这几个部分的执行顺序。然后,只要替换具体的建造者,就能得到不同的具体产品。
画小人的例子:建造者父类定义画头,画手,画脚等各个接口;具体的建造者实现画的过程(胖的,瘦的等等);指挥者定义一个画的方法,规定画的顺序(头-》手-》脚)。
指挥者只要调用不同的具体假造者,就能得到想要的小人(胖的还是瘦的)
结构型模式(7种)
-
代理
简单说就是外面再包一层;
追mm的例子:
首先定义一些接口方法,比如送花,送巧克力等等。实际的追求者,实现这些接口(具体做事的);代理也实现接口,只是代理不会自己来做这些事,而是内部包含一个追求者的成员变量,通过调用追求者来实现接口方法;
客户端调用代理来完成任务,不会直接调用实际的实现者。 -
适配器
目的是使用现有的功能
客户端需要的方法,抽象为一个父类;各个子类实现这些方法;现在,有一个类,功能复合要求,但是不遵循父类定义的接口。这个时候就需要一个适配器。
适配器遵循父类定义的接口;但是实现接口的时候,通过调用作为成员变量的第三类来实现。所以适配器只是做了接口转换,没有做实际的事情。
NBA翻译的例子:
NBA打球交流都是说英文;但是姚明说中文;这个时候就需要一个翻译;这个翻译就是适配器;
翻译实现英文的接口,但是内部调用姚明完成具体的工作; -
装饰
目的是动态添加功能;
被装饰的目标作为父类;
装饰类继承父类,并且还将装饰对象作为成员变量;
添加新功能,并执行原有功能,这样就加上去了;
穿衣的例子:
人作为父类;衣服继承,并且里面包含一个人的成员变量;
可以添加衣服,并且可以调用成员变量的人(包括衣服的人)进行原有功能的展示; -
外观
在现有系统之上再定义一层,方便使用;
基金的例子:
股票、国债有好多种,一个个对接,比较麻烦;引入基金作为外观,对外提供买和卖两个简单接口。基金内部,将股票、国债等都当做成员变量;基金买,内部其实是股票和国债买;基金卖,其实是股票和国债卖;
APP后台也是这样来的例子;如果APP直接对接业务系统,那接起来就会很麻烦;APP后台综合一下,就能提供简洁好用的接口; -
桥接
抽象和实现分离,可以各自独立变化。
手机软硬件分离的例子:
手机软件有基类;派生出游戏通讯录等各种具体软件;
手机硬件有基类;派生出苹果,华为,小米等各种品牌;
然后,手机软件作为手机硬件的一个成员就可以表达:华为手机的通讯录这样的意思了。 -
组合
指树形结构图,分为基类,树枝,叶子三种不同的角色
公司结构图的例子:
公司类就是积累,定义添加、删除、展示等公共方法;
子公司,有下属部门的属于树枝类,是公司类的子类;
部门,没有下属部门的那种,属于树叶类,是公司类的子类; -
享元
用共享的方式减少实例的数量;
例子:做网站;
把创建的网站实例通过key/value
的方式缓存在一个hash
表中;没有就新建,有就用hash
表中的;
行为型模式(11种)
-
策略
把算法封装起来,可以方便地相互替换。
商场打折的例子:
定义一个算法基类,规定算法接口;
算法子类,实现具体的算法,比如打折,满XX送YY之类的;
上下文类,包含一个算法类作为成员;更换算法成员,就能切换不同的算法。 -
模板方法
公共部分放在基类中,特定部分放在子类中。
考试卷的例子:
试题部分放在基类中,解答部分放在子类中。 -
观察者
主题(或者说通知中心)主要有添加、删除观察者,发出通知等功能;
观察者接收通知,然后做相应的动作。
iOS中有观察消息的接口,通知中心是系统做好的,不需要另外写; -
迭代
顺序访问;主要定义第一个,下一个,是否结束,当前元素等接口;iOS中的NSArray有现成的迭代器,不需要写。
自定义类的构造器:自定义的集合类作为迭代器的构造参数。 -
职责链
Handler作为基类,主要定义两个方法,处理请求,设置上级;处理的内容包装成一个Request类进行传递。
如果能处理,就处理,退出;
如果不能处理,就调用上级的处理方法,进行Request的传递;
链的出口只有处理方法,没有上级;
小菜请假加薪的例子;
小菜的请求包装成一个Request;
经理,总监,总经理等都是一条职责链中的Handler; -
命令
在调用者和执行者之间加入了一个命令对象;
调用者保存一个命令数组,可以添加,删除命令;
命令对象包含具体的执行者(成员变量)。调用者调用命令对象的执行方法,执行者开始做具体的事情;
烤肉店的例子:
服务员就是调用者;
菜单就是命令对象;
厨师就是执行者;
runtime的消息机制有点像这个;
iOS网络访问可以使用这个模式; -
备忘录
备忘录对象是一个状态对象,是一个数据结构对象,是保存恢复的一个数据集合;
使用者可以保存,恢复数据对象(备忘录);
协助者,持有数据对象的集合;
游戏的例子:
可以将游戏的数据封装成一个备忘录对象(攻击,防御,生命等数据);
游戏主体就是使用者,可以保存数据(存档),也可以恢复数据(读挡);
各种存档放在一个协助者中暂存,存档是往协助者送备忘录,读挡时从协助者拿备忘录; -
状态
状态对象基类定义状态方法,各种子类定义各种不同的状态;
上下文对象保存状态判断条件,以及当前状态;
状态对象在执行的时候需要上下文作为参数;
所以,上下文和状态是相互关联的;
小菜写程序状态的例子:
上午、下午,傍晚等各种状态就是不同的状态子类;
工作对象就是上下文类;
各种状态类通过work类中条件判断是不是自己,是的话就展示,不是的话就通过调用work类中current进行状态流转; -
访问者
数据对象,有多个,一般数量稳定,比如男人,女人,就两种;提供一个accept方法,入参是个访问者;数据对象会存放在一个数据对象集合中;
访问者;可扩展,对每个数据对象提供一个方法,入参是数据对象;
男人女人的例子:
这里的访问者是成功,失败,婚恋等等各种话题,展示男人、女人队这些话题的不同态度;
数据对象个数是固定的,比如只有男人、女人两种;
访问者(这里是话题)是可以随时扩展的; -
中介者
中介对象,包含所有其他对象,其他对象只跟中介沟通,相互之间不沟通;
其他对象
联合国的例子:
联合国就是中介对象;其他各个国家都是联合国的成员;
谁想发言,就在联合国留言;其他成员想看,就去联合国的留言区就可以了; -
解释器
自定义语义翻译,比如字母H表示高速,L表示低速;输入一串文本,输出高速低速等文字
自己写的文章
多线程
- 自定义NSOperation需要重写的方法
// 对于并发的Operation需要重写改方法
- (void)start;
// 非并发的Operation需要重写该方法
- (void)main;
- 实现并发的自定义子类,需要重写下面几个方法或属性:
start:把需要执行的任务放在start方法里,任务加到队列后,队列会管理任务并在线程被调度后,调用start方法,不需要调用父类的方法
asynchronous:表示是否并发执行
executing:表示任务是否正在执行,需要手动调用KVO方法来进行通知,方便其他类监听了任务的该属性
finished:表示任务是否结束,需要手动调用KVO方法来进行通知,队列也需要监听改属性的值,用于判断任务是否结束
网友评论