美文网首页
GeekBand iOS开发高级进阶学习笔记(第三周)

GeekBand iOS开发高级进阶学习笔记(第三周)

作者: Hysoka | 来源:发表于2016-05-01 13:10 被阅读67次

    多线程的概念

    进程 Process:是正在运行程序的实例,是一个具有一定独立功能的程序关于某个数据集合的一次运行活动,一个进程中可以有多个线程。

    线程 Thread:是程序执行流的最小单元,是进程中的一个实体,被系统独立调度和分派的基本单位。每一个程序都至少有一个线程,若程序只有一个线程,那就是程序本身。

    在iOS编程中有三套API用来控制多线程操作
    1、定义工作同时进行调度的有 POSIX threads 和 NSThread。POSIX threads是C语言的API,NSThread是对POSIX threads的封装,是OC的API。

    2、基于一个任务来调度的有NSOperation, NSBlockOperation, NSInvocationOperation

    3、还有一套是用来管理进程队列的,NSOperationQueue和Dispatch Queue。Dispatch Queue也是基于C语言的API使用比较灵活,也是目前最长用的一套API。

    多线程的API

    MainThread
    程序启动后,系统会自动创建一个主线程,也叫UI线程。如果主线程阻塞,UI就会失去响应,所有的UI操作都应该放到主线程中去执行。因此为了不妨碍UI执行的流畅程度,时间长、计算量大、阻塞IO都应该另外开辟分线程来执行。

    用NSThread开新线程执行
    新开线程的方法
    +(void)detachNewThreadSelector:(SEL) toTarget:(id) withObject:(id)
    也可以用自定义NSThread实例
    在NSThread的子类里重载 -(void)main
    -initWithTarget:(id) selector:(SEL) object:(id)
    [thread start]
    回主线程中执行

    -(void)[anyNSObject performSelectorOnMainThread:(SEL) withObject:(nullable id) waitUntilDone:(BOOL)]
    +(BOOL)isMainThread  //返回一个值判断是否为主线程
    

    创建线程也是有开销的

    创建线程的开销

    线程属性及线程内部存储(TLS)
    .name 线程的名字
    .stackSize 设置线程栈的大小,单位是字节(byte)由于内存对齐的原因必须设置为4K的整数倍,要在线程启动前设置才起作用。
    threadPriority 线程的优先级设置[0.0 1.0]
    TLS
    NSMutableDictionary *thread.threadDicitionary //线程的存储空间

    线程控制
    启动指定线程
    start 开始线程
    canecl 取消开始线程

    停止当前线程
    +currentThread 获取当前线程
    +sleepUntilDate:(NSDate *) 线程休眠(到指定的时间)
    +sleepForTimeInterval:(NSTimeInterval) 线程休眠(指定秒数)
    +exit 强行停止线程,尽量少用

    线程与事件响应
    除了Touches,还有网络、定时器等其他事件,等候这些事件出现时,不能锁住界面,然而线程不停轮询所有事件源有太浪费,我们可以将计算机调度与事件查询分开。体统将事件查询功能交给NSRunLoop来做。

    NSRunLoop RunLoop Mode

    每一个RunLoop可以有多个Mode每一个Mode都有3个集合,分别是Source,Observer,Timer

    预定义的RunLoop Mode

    Common Modes
    加到这个模式里的Item,会关联到该RunLoop的所有Mode上。保证了所有Mode中这个Item都会被触发。
    自定义Mode可以标记自己是Common的,调用CFRunLoopAddCommonMode()这个方法会把这个Mode名字加到_commonModes Set里。
    系统提供的mode都是Common Modes。

    NSRunLoop的生命周期


    rllt.jpg

    主线程的观察者会在进入RunLoop时创建一个autorelease pool,当线程即将睡眠的时候主线程的观察者会创建一个新的autorelease pool,并将旧的autorelease pool释放掉,下一轮就用新的autorelease pool。当这一轮的RunLoop退出时,主线程的观察者会释放掉autorelease pool。
    主线程会注册一个Source1以接收HIDEvent。
    当线程将要进入睡眠时或RunLoop要退出时,主线程的观察者会遍历界面,将有变动的界面重新布局和绘制。
    受其他动作的影响,Timer的触发事件并不精确,受动作影响如果Timer的时间点已经超过,就会跳过这次响应。

    通过NSObject给线程添加任务

    NSOpertaion
    我们使用线程是为了完成一个费时的任务,且不影响UI响应,NSOperation是对线程任务进行了封装:
    用selector编写任务:NSInvocationOperation
    用block编写任务:NSBlockOperation
    任务可以用依赖关系串起来
    NSOperationQueue:封装线程管理部分

    NSOperation是一个抽象基类,不可以直接使用,必须使用其子类。
    执行动作
    向NSOperation发送start消息用来 启动(在当前线程中执行)
    其内部的执行就是设置状态然后调用main方法
    向NSOperation发送cancel消息用来 取消
    waitUntilFinished

    任务定义
    main 方法默认什么也不干,但是会在NSOperation提供的AutoreleasePoo里运行
    定义NSOperation子类时覆盖

    NSInvocationOperation
    创建

    -initWithTarget:(id) selector:(SEL) object:(id)
    -initWithInvocation:(NSInvocation *) 
    //NSInvocation *是一个由(id) selector:(SEL) object:(id)组成的对象
    

    NSBlockOperation
    创建
    +blockOperationWithBlock:(void (^) (void))
    追加
    -(void)addExecutionBlock:(void(^)(void))
    Operation会copy参数block

    NSOperation可以使用依赖关系
    -(void)addDependency:(NSOperation *)dep
    dep完成后,本Operation才会开始执行(注意不要写成循环依赖)。依赖链中的Operation即使已经完成,也不会从链中移出,除非调用-removeDependency。

    NSOperation的状态
    .name 名字
    .ready 准备好开始
    .executing 运行
    .finished 运行结束
    .cancelled 取消
    .asynchronous 异步或同步
    默认是NO,只读,只有子类能修改
    synchronized, in calling thread
    -setCompletionBlock:(^(void))

    NSOperationQueue
    Queue operations 队列操作
    add 将一个NSOperation添加到NSOperationQueue中

    [q addOperation:anOp]; //添加一个NSOperation
    [q addOperations:anArrayofOps waitUntilFinished:NO]; //添加一个NSOperation集合
    [q addOperationWithBlock:^{...}];
    

    运行控制

    -setMaxConcurrentOperationCount: //设置线程队列里最多可以有几个任务
    -addDependency //添加一个运行依赖
    -cancelAllOperation //将队列中的所有任务全部取消
    -setSuspended:(BOOL) //队列本身暂停
    waitUnitlAllOperationAreFinished //当队列中的所有任务执行完毕后我们可以在用这个方法再添加操作
    

    Main Queue
    +mainQueue 调用该方法就可以得到主线程的对象
    operations will serially run on main thread in common runloop mode

    多线程 GCD
    GCD是Grand Central Dispatch的缩写,他是一个C语言API,是Apple开发的一个多核编程的解决方法。
    dispatch queue分成Main queue, global dispatch queue, serial queue三种。
    用法:获取一个queue,然后dispatch a block using the queue(使用分发模块的方法使用队列)。
    在Objective-C里,dispatch objects也是ObjectC对象,支持ARC。

    获取一个队列:
    Global Concurrent Queue:
    dispatch_get_global_queue(id,0)
    这个函数返回一个dispatch_queue_t类型,第二个参数永远是0(设计时为了以后扩展,目前填0)
    第二个参数id:填写的是任务的优先级,从高到低是:DISPATCH_QUEUE_PRIORITY_HIGH/DEFAULF/LOW/BACKGROUND
    也有新的表达方式依然是优先级从高到低参数为:QOS_CLASS_USER_INTERACTIVE/INITIATED/UTILITY/BA CKGROUND

    Main Queue(serial)

    dispatch_get_main_queue(); //将主线程拿回来
    

    ~~dispatch_main(); ~~在MAC OS上调用,iOS编程用不到。

    Create Queue
    我们自己创建的只能是串行队列
    dispatch_queue_create("com.my.q",NULL);
    这里第一个参数是队列的名字(是C语言字符串)

    Queue OP
    暂停和恢复运行一个队列
    dispatch_suspend()/diepatch_resume()

    在队列退出时进行调用,可以做一些清理的工作
    on queue cleanup:dispatch_set_finalizer_f(func)
    -void myFinalizerFunction(void *context)

    拿到队列后我们可以开始分配任务
    dispatch_sync(q,block): don't do this on q's thread 用的比较少,当前的block会等待线程完成后再返回
    dispatch_async(q,block) 将block放入队列后就返回
    on task complete:dispatch a block at end of task
    dispatch inside
    dispatch_retain(q)before queue the task
    dispatch_release(q)before queue complete block

    get queue in block: dispatch_get_current_queue() 获取当前执行的队列

    用Context传递参数,可以给队列定义一个Context来传递数据

    dispatch_set_context(q,voidPtr)
    dispatch_get_context(q,voidPtr)
    

    singleton 确保任务只执行一次
    dispatch_once(dispatch_once_t *,block);

    timer 在一段时间后开始执行
    dispatch_after(dispatch_time_t, q, block);

    for-loop 循环执行
    dispatch_apply(count,q,^(size_t i){...})

    Dispatch Group

    dispatch_group_tgroup = dispatch_group_create();  //创建一个组
    dispatch_group_async(g, q,^{});
    dispatch_gruop_wait(g) //在这个组的任务全部完成后开始动作
    

    同步
    dispatch_semaphore_t 信号量

    dispatch_semaphore_create(long) 
    long dispatch_semaphore_wait(sema, timeout); 
    dispatch_semaphore_signal(sema)
    

    barrier 临界区

    dispatch_barrier_async(q,block)
    dispatch_barrier_sync(q,block)
    

    Dispatch Source

    Dispatch Source

    分享一个GCD的代码例子:http://www.cnblogs.com/pure/archive/2013/03/31/2977420.html

    相关文章

      网友评论

          本文标题:GeekBand iOS开发高级进阶学习笔记(第三周)

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