美文网首页
iOS问题搜集-2021-02-05-周五

iOS问题搜集-2021-02-05-周五

作者: 勇往直前888 | 来源:发表于2021-03-18 17:40 被阅读0次

    RAC冷热信号

    概念区别

    1. Hot Observable是主动的,尽管你并没有订阅事件,但是它会时刻推送,就像鼠标移动;
      而Cold Observable是被动的,只有当你订阅的时候,它才会发布消息。

    2. 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操作,那么一定要发送完成信号,不然会内存泄漏。

    ReactiveCocoa中潜在的内存泄漏及解决方案

    使用简介

    IOS RAC使用 -- ReactiveObjC

    关于ReactiveObjC使用简介

    性能

    性能监控

    美团的案例: 移动端性能监控方案Hertz

    离屏渲染

    iOS离屏渲染以及切圆角所产生的离屏渲染

    iOS离屏渲染原理和优化

    iOS离屏渲染之优化分析

    启动时间

    优化 App 的启动时间实践 iOS

    iOS启动时间优化

    iOS App 启动性能优化

    设计模式

    面向对象三大特性

    封装,继承,多态

    五大设计原则

    1. 单一职责
    2. 开放闭合
    3. 依赖倒转
    4. 里氏代换
    5. 迪米特法则

    创建型模式(5种)

    这几个模式都是关于类的创建的。

    1. 工厂方法
      简单工厂:例子是加减乘除计算器;基类产品定义接口(两个操作数,一个计算操作);子类产品就是具体的加减乘除具体的计算;工厂对应基类,建造的时候要输入一个字符串指定类型,工厂内有switch语句判断;
      工厂方法就是把switch语句优化掉,每种具体的计算类都配一个工厂,让客户端决定需要的工厂来创建相应的产品。

    2. 抽象工厂
      例子是更换数据库;产品有多个,比如用户,部门等等;数据库也有多种,比如Sql和Access。
      把相关联的产品(用户,部门等)的创建方法接口集合在一起,形成一个系列;具体的工厂(Sql,Access等等)实现这些创建方法;
      结合反射技术,更换数据的库的时候,只要更换相应的配置文件就可以了;

    3. 单例
      保证一个类只有一个实例,并提供一个全局访问点,一般是getInstance()方法;iOS中的dispatch_once非常适合做这个。

    4. 原型
      实现clone()接口,通过复制一个对象来创建一个新对象;

    5. 建造者
      对象建造需要分为几个部分,这几个部分的顺序基本不变。每个部分的内部具体实现可以变化。可以定义一个建造者,定义各个部分的接口;具体的建造者实现这些部分的接口;再定义一个指挥者,定义一个建造方法,规定这几个部分的执行顺序。然后,只要替换具体的建造者,就能得到不同的具体产品。
      画小人的例子:建造者父类定义画头,画手,画脚等各个接口;具体的建造者实现画的过程(胖的,瘦的等等);指挥者定义一个画的方法,规定画的顺序(头-》手-》脚)。
      指挥者只要调用不同的具体假造者,就能得到想要的小人(胖的还是瘦的)

    结构型模式(7种)

    1. 代理
      简单说就是外面再包一层;
      追mm的例子:
      首先定义一些接口方法,比如送花,送巧克力等等。实际的追求者,实现这些接口(具体做事的);代理也实现接口,只是代理不会自己来做这些事,而是内部包含一个追求者的成员变量,通过调用追求者来实现接口方法;
      客户端调用代理来完成任务,不会直接调用实际的实现者。

    2. 适配器
      目的是使用现有的功能
      客户端需要的方法,抽象为一个父类;各个子类实现这些方法;现在,有一个类,功能复合要求,但是不遵循父类定义的接口。这个时候就需要一个适配器。
      适配器遵循父类定义的接口;但是实现接口的时候,通过调用作为成员变量的第三类来实现。所以适配器只是做了接口转换,没有做实际的事情。
      NBA翻译的例子:
      NBA打球交流都是说英文;但是姚明说中文;这个时候就需要一个翻译;这个翻译就是适配器;
      翻译实现英文的接口,但是内部调用姚明完成具体的工作;

    3. 装饰
      目的是动态添加功能;
      被装饰的目标作为父类;
      装饰类继承父类,并且还将装饰对象作为成员变量;
      添加新功能,并执行原有功能,这样就加上去了;
      穿衣的例子:
      人作为父类;衣服继承,并且里面包含一个人的成员变量;
      可以添加衣服,并且可以调用成员变量的人(包括衣服的人)进行原有功能的展示;

    4. 外观
      在现有系统之上再定义一层,方便使用;
      基金的例子:
      股票、国债有好多种,一个个对接,比较麻烦;引入基金作为外观,对外提供买和卖两个简单接口。基金内部,将股票、国债等都当做成员变量;基金买,内部其实是股票和国债买;基金卖,其实是股票和国债卖;
      APP后台也是这样来的例子;如果APP直接对接业务系统,那接起来就会很麻烦;APP后台综合一下,就能提供简洁好用的接口;

    5. 桥接
      抽象和实现分离,可以各自独立变化。
      手机软硬件分离的例子:
      手机软件有基类;派生出游戏通讯录等各种具体软件;
      手机硬件有基类;派生出苹果,华为,小米等各种品牌;
      然后,手机软件作为手机硬件的一个成员就可以表达:华为手机的通讯录这样的意思了。

    6. 组合
      指树形结构图,分为基类,树枝,叶子三种不同的角色
      公司结构图的例子:
      公司类就是积累,定义添加、删除、展示等公共方法;
      子公司,有下属部门的属于树枝类,是公司类的子类;
      部门,没有下属部门的那种,属于树叶类,是公司类的子类;

    7. 享元
      用共享的方式减少实例的数量;
      例子:做网站;
      把创建的网站实例通过key/value的方式缓存在一个hash表中;没有就新建,有就用hash表中的;

    行为型模式(11种)

    1. 策略
      把算法封装起来,可以方便地相互替换。
      商场打折的例子:
      定义一个算法基类,规定算法接口;
      算法子类,实现具体的算法,比如打折,满XX送YY之类的;
      上下文类,包含一个算法类作为成员;更换算法成员,就能切换不同的算法。

    2. 模板方法
      公共部分放在基类中,特定部分放在子类中。
      考试卷的例子:
      试题部分放在基类中,解答部分放在子类中。

    3. 观察者
      主题(或者说通知中心)主要有添加、删除观察者,发出通知等功能;
      观察者接收通知,然后做相应的动作。
      iOS中有观察消息的接口,通知中心是系统做好的,不需要另外写;

    4. 迭代
      顺序访问;主要定义第一个,下一个,是否结束,当前元素等接口;iOS中的NSArray有现成的迭代器,不需要写。
      自定义类的构造器:自定义的集合类作为迭代器的构造参数。

    5. 职责链
      Handler作为基类,主要定义两个方法,处理请求,设置上级;处理的内容包装成一个Request类进行传递。
      如果能处理,就处理,退出;
      如果不能处理,就调用上级的处理方法,进行Request的传递;
      链的出口只有处理方法,没有上级;
      小菜请假加薪的例子;
      小菜的请求包装成一个Request;
      经理,总监,总经理等都是一条职责链中的Handler;

    6. 命令
      在调用者和执行者之间加入了一个命令对象;
      调用者保存一个命令数组,可以添加,删除命令;
      命令对象包含具体的执行者(成员变量)。调用者调用命令对象的执行方法,执行者开始做具体的事情;
      烤肉店的例子:
      服务员就是调用者;
      菜单就是命令对象;
      厨师就是执行者;
      runtime的消息机制有点像这个;
      iOS网络访问可以使用这个模式;

    7. 备忘录
      备忘录对象是一个状态对象,是一个数据结构对象,是保存恢复的一个数据集合;
      使用者可以保存,恢复数据对象(备忘录);
      协助者,持有数据对象的集合;
      游戏的例子:
      可以将游戏的数据封装成一个备忘录对象(攻击,防御,生命等数据);
      游戏主体就是使用者,可以保存数据(存档),也可以恢复数据(读挡);
      各种存档放在一个协助者中暂存,存档是往协助者送备忘录,读挡时从协助者拿备忘录;

    8. 状态
      状态对象基类定义状态方法,各种子类定义各种不同的状态;
      上下文对象保存状态判断条件,以及当前状态;
      状态对象在执行的时候需要上下文作为参数;
      所以,上下文和状态是相互关联的;
      小菜写程序状态的例子:
      上午、下午,傍晚等各种状态就是不同的状态子类;
      工作对象就是上下文类;
      各种状态类通过work类中条件判断是不是自己,是的话就展示,不是的话就通过调用work类中current进行状态流转;

    9. 访问者
      数据对象,有多个,一般数量稳定,比如男人,女人,就两种;提供一个accept方法,入参是个访问者;数据对象会存放在一个数据对象集合中;
      访问者;可扩展,对每个数据对象提供一个方法,入参是数据对象;
      男人女人的例子:
      这里的访问者是成功,失败,婚恋等等各种话题,展示男人、女人队这些话题的不同态度;
      数据对象个数是固定的,比如只有男人、女人两种;
      访问者(这里是话题)是可以随时扩展的;

    10. 中介者
      中介对象,包含所有其他对象,其他对象只跟中介沟通,相互之间不沟通;
      其他对象
      联合国的例子:
      联合国就是中介对象;其他各个国家都是联合国的成员;
      谁想发言,就在联合国留言;其他成员想看,就去联合国的留言区就可以了;

    11. 解释器
      自定义语义翻译,比如字母H表示高速,L表示低速;输入一串文本,输出高速低速等文字

    自己写的文章

    大话设计模式Android版

    多线程

    • 自定义NSOperation需要重写的方法
    // 对于并发的Operation需要重写改方法
    - (void)start;
    
    // 非并发的Operation需要重写该方法
    - (void)main;
    
    • 实现并发的自定义子类,需要重写下面几个方法或属性:

    start:把需要执行的任务放在start方法里,任务加到队列后,队列会管理任务并在线程被调度后,调用start方法,不需要调用父类的方法
    asynchronous:表示是否并发执行
    executing:表示任务是否正在执行,需要手动调用KVO方法来进行通知,方便其他类监听了任务的该属性
    finished:表示任务是否结束,需要手动调用KVO方法来进行通知,队列也需要监听改属性的值,用于判断任务是否结束

    彻底了解NSOperation的自定义

    参考文章

    2020:一份高级iOS面试题

    iOS面试题及答案.及添加React Native面试题 随时更新

    相关文章

      网友评论

          本文标题:iOS问题搜集-2021-02-05-周五

          本文链接:https://www.haomeiwen.com/subject/rrnwtltx.html