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

多线程的概念

进程 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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,884评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,347评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,435评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,509评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,611评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,837评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,987评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,730评论 0 267
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,194评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,525评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,664评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,334评论 4 330
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,944评论 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,764评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,997评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,389评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,554评论 2 349

推荐阅读更多精彩内容