美文网首页
iOS 2019年3月学习记录

iOS 2019年3月学习记录

作者: quantiza | 来源:发表于2019-03-18 17:19 被阅读0次

    1、KVC与KVO

    1.1 描述
    1)KVC是key-value coding,通过key-value形式直接访问或修改对象属性,这中运行时动态特性可以方便地实现诸多功能。
    2)KVO是key-value observing,这是一种观察者模式,通过监听key,来获得value的变化,用来在对象之间监听状态变化。
    1.2 原理
    1)KVC 当调用当调用setValue:value forKey:@”key“的代码时,执行如下操作

    image.png
    2)KVO 是通过 isa-swizzling 实现的。
    • 当某个类的对象第一次被观察时,系统就会在运行期动态地创建该类的一个派生类,在这个派生类中重写基类中任何被观察属性的 setter 方法。
    • 派生类在被重写的 setter 方法中实现真正的通知机制,就如前面手动实现键值观察那样。这么做是基于设置属性会调用 setter 方法,而通过重写就获得了 KVO 需要的通知机制。当然前提是要通过遵循 KVO 的属性设置方式来变更属性值,如果仅是直接修改属性对应的成员变量,是无法实现 KVO 的。
    • 同时派生类还重写了 class 方法以“欺骗”外部调用者它就是起初的那个类。然后系统将这个对象的 isa 指针指向这个新诞生的派生类,因此这个对象就成为该派生类的对象了,因而在该对象上对 setter 的调用就会调用重写的 setter,从而激活键值通知机制。此外,派生类还重写了 dealloc 方法来释放资源。
    image.png

    1.3 接口

    NSKeyValueCoding.h
    - (nullable id)valueForKey:(NSString *)key;
    - (void)setValue:(nullable id)value forKey:(NSString *)key;
    - (nullable id)valueForKeyPath:(NSString *)keyPath;
    - (void)setValue:(nullable id)value forKeyPath:(NSString *)keyPath;
    NSKeyValueObserving.h
    //Registration
    - (void)addObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options context:(nullable void *)context;
    //Observing
    - (void)observeValueForKeyPath:(nullable NSString *)keyPath ofObject:(nullable id)object change:(nullable NSDictionary<NSKeyValueChangeKey, id> *)change context:(nullable void *)context;
    //Notification
    - (void)willChangeValueForKey:(NSString *)key;
    - (void)didChangeValueForKey:(NSString *)key;
    //remvoe
      ...
    //Customization
    + (NSSet<NSString *> *)keyPathsForValuesAffectingValueForKey:(NSString *)key // 属性依赖
    + (BOOL)automaticallyNotifiesObserversForKey:(NSString *)key; // 是否自动添加通知代码
    

    1.4 线程?同步
    1.5 资料

    1.6 问题
    如何手动触发一个value的KVO?
    KVC的keyPath中的集合运算符如何使用?
    KVC和KVO的keyPath一定是属性么?
    如何关闭默认的KVO的默认实现,并进入自定义的KVO实现?
    apple用什么方式实现对一个对象的KVO?

    2、Runloop

    2.1 Runloop概述
    线程创建后任务执行完成,线程就会销毁。为了构造常驻线程处理事件,引入了EventLoop机制。iOS/OSX系统内的这种机制被称为Runloop。Runloop是一个对象,该对象用来管理需要处理的事件和消息其操作流程为:

    runloop:
    do {
      get message
      handle message
      wait
    } while (message != quit)
    

    2.2 Runloop与线程关系

    • 线程和 RunLoop 之间是一一对应的,其关系是保存在一个全局的 Dictionary 里。
    • 线程刚创建时并没有 RunLoop,如果你不主动获取,那它一直都不会有。两个自动获取的函数:CFRunLoopGetMain()CFRunLoopGetCurrent()
    • RunLoop 的创建是发生在第一次获取时,RunLoop 的销毁是发生在线程结束时。

    2.3 RunloopMode
    1)一个 RunLoop 包含若干个 Mode,每个 Mode 又包含若干个 Source/Timer/Observer。每次调用 RunLoop 的主函数时,只能指定其中一个 Mode,这个Mode被称作 CurrentMode。如果需要切换 Mode,只能退出 Loop,再重新指定一个 Mode 进入。这样做主要是为了分隔开不同组的 Source/Timer/Observer,让其互不影响。


    image.png image.png

    2)Source/Timer/Observer统称为mode item, 一个 item 可以被同时加入多个 mode,如果mode中没有item直接退出Runloop,不进入循环 。


    image.png
    • CFRunLoopSourceRef 是事件产生的地方,包括source0和source1。source0是非内核消息需要手动唤醒Runloop,source1是内核消息自动唤醒Runloop。
    • CFRunLoopTimerRef 注册时间,时间到时触发Runloop
    • CFRunLoopObserverRef 会接收到Runloop的状态变化包括:
    typedef CF_OPTIONS(CFOptionFlags, CFRunLoopActivity) {
        kCFRunLoopEntry         = (1UL << 0), // 即将进入Loop
        kCFRunLoopBeforeTimers  = (1UL << 1), // 即将处理 Timer
        kCFRunLoopBeforeSources = (1UL << 2), // 即将处理 Source
        kCFRunLoopBeforeWaiting = (1UL << 5), // 即将进入休眠
        kCFRunLoopAfterWaiting  = (1UL << 6), // 刚从休眠中唤醒
        kCFRunLoopExit          = (1UL << 7), // 即将退出Loop
    };
    

    3)一个 Mode 可以将自己标记为”Common”属性(CFRunLoopAddCommonMode(CFRunLoopRef runloop, CFStringRef modeName);)。苹果公开提供的 Mode 有两个:kCFRunLoopDefaultMode (NSDefaultRunLoopMode)UITrackingRunLoopMode,都已经标记为common属性
    2.4 Runloop内部逻辑
    简单来讲,根据observer的状态分别处理Timer,source0,source1消息,然后进入休眠等等这些消息继续唤醒。
    2.5 Runloop底层实现
    2.6 Runloop应用

    • AutoreleasePool ,主线程会注册两个observer,监控_objc_autoreleasePoolPop() 和 _objc_autoreleasePoolPush() 的发生时机
    • 后台常驻线程
    • 定时器
    • 卡顿监测

    2.7 问题
    runloop和线程有什么关系?
    runloop的mode作用是什么?
    猜想runloop内部是如何实现的?(通过循环实现循环体大概内容,点到即可)

    2.8 参考
    深入理解RunLoop
    深入浅出 RunLoop
    runloop应用系列
    Threading Programming Guide - Run Loops

    3.并发编程的挑战和应对之策

    3.1 挑战
    多线程导致Data Race,加锁导致Dead Lock, Starvation,Priority Inversion

    • Data Race
    • Dead Lock
    • Starvation
    • Priority Inversion (所以通常不要使用不同的优先级,gcd中使用默认优先级)
    image.png

    3.2 Semaphore(信号量)
    类比20人去只有10个位的餐厅吃饭

    • count = 10,10个座位。
    • queue,餐厅位置有限,为了避免混乱,餐厅肯定会吃货们排队。
    • wait(),吃货到了餐厅找服务员要位置点餐,这个行为就是wait。
    • signal(),吃货吃完了买单离开位置,这个行为就是signal。
      3.2 Mutex(互斥量)
      3.3 Lock(锁)
      对mutex的封装
      3.3 Condition(条件变量)

    相关文章

      网友评论

          本文标题:iOS 2019年3月学习记录

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