Skip to content

Commit b4afc02

Browse files
committed
修改iOS多线程处文章风格
1 parent a503663 commit b4afc02

File tree

2 files changed

+27
-31
lines changed

2 files changed

+27
-31
lines changed

source/iOS/Cocoa-Touch/Multithreading.md

Lines changed: 20 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ Cocoa 中封装了 NSThread, NSOperation, GCD 三种多线程编程方式,他
1616

1717
* NSOperation
1818

19-
NSOperation 是一个抽象类,它封装了线程的细节实现,不需要自己管理线程的生命周期和线程的同步和互斥等。只是需要关注自己的业务逻辑处理,需要和 NSOperationQueue 一起使用。使用 NSOperation 时,你可以很方便的设置线程之间的依赖关系。这在略微复杂的业务需求中尤为重要。(在此后的GCD烧脑体操中,你将会深刻体会)
19+
NSOperation 是一个抽象类,它封装了线程的细节实现,不需要自己管理线程的生命周期和线程的同步和互斥等。只是需要关注自己的业务逻辑处理,需要和 NSOperationQueue 一起使用。使用 NSOperation 时,你可以很方便的设置线程之间的依赖关系。这在略微复杂的业务需求中尤为重要。
2020

2121
* GCD
2222

@@ -172,15 +172,13 @@ printf("两个 block 都已经执行完毕\n");
172172
* 避免在任务中使用锁,如果使用锁的话可能会阻碍 queue 中其他 task 的运行
173173
* 不建议获取 dispatch_queue 底层所使用的 thread 的有关信息,也不建议在 queue 中再使用 pthread 系函数
174174
175-
#### GCD烧脑体操
175+
#### GCD 案例分析
176176
177-
说了 GCD 这么多,不如来几道烧脑体操吧,也借此机会体会一下 GCD。
178-
179-
##### 烧脑体操第一节
177+
##### 案例一
180178
181179
这是一个广为流传的例子,代码如下:
182180
183-
```
181+
```objectivec
184182
NSLog(@"1"); // 任务1
185183
dispatch_sync(dispatch_get_main_queue(), ^{
186184
NSLog(@"2"); // 任务2
@@ -208,19 +206,19 @@ NSLog(@"3"); // 任务3
208206

209207
主线程启动以后的加入顺序是:任务1,同步线程,任务三。执行完任务1,就会启动同步线程,然后将任务2加入队列。所以,任务3在任务2的前面。如图中所示的那样,这种情况下 任务2 与 任务 3都在等待彼此完成之后才能执行,这就造成了死锁。
210208

211-
##### 烧脑体操第二节
209+
##### 案例二
212210

213-
这个例子由此前的第一节演化而来,代码如下
211+
这个例子由此前的案例一演化而来,代码如下
214212

215-
```
213+
```objectivec
216214
NSLog(@"1"); // 任务1
217215
dispatch_sync(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
218216
NSLog(@"2"); // 任务2
219217
});
220218
NSLog(@"3"); // 任务3
221219
```
222220
223-
正如你所期待的那样,这并不会造成死锁,控制台输出如下:
221+
这并不会造成死锁,控制台输出如下:
224222
225223
```
226224
1
@@ -234,13 +232,13 @@ NSLog(@"3"); // 任务3
234232
235233
分析与过程描述:
236234
237-
首先执行任务1,接下来会遇到一个同步线程,程序会进入等待。等待任务2执行完成以后,才能继续执行任务3。从dispatch_get_global_queue可以看出,任务2被加入到了全局的并行队列中,当并行队列执行完任务2以后,返回到主队列,继续执行任务3。
235+
首先执行任务1,接下来会遇到一个同步线程,程序会进入等待。等待任务2执行完成以后,才能继续执行任务3。从 dispatch_get_global_queue 可以看出,任务2被加入到了全局的并行队列中,当并行队列执行完任务2以后,返回到主队列,继续执行任务3。
238236
239-
##### 烧脑体操第三节
237+
##### 案例三
240238
241239
这个例子会比此前的两节复杂一些,代码如下:
242240
243-
```
241+
```objectivec
244242
dispatch_queue_t queue = dispatch_queue_create("com.demo.serialQueue", DISPATCH_QUEUE_SERIAL);
245243
NSLog(@"1"); // 任务1
246244
dispatch_async(queue, ^{
@@ -262,7 +260,6 @@ NSLog(@"5"); // 任务5
262260
// 5和2的顺序不一定
263261
```
264262

265-
266263
分析:这里没有使用系统提供的串行或并行队列,而是自己通过dispatch_queue_create函数创建了一个`DISPATCH_QUEUE_SERIAL`的串行队列。
267264

268265
如图所示:
@@ -277,13 +274,11 @@ NSLog(@"5"); // 任务5
277274
4. 任务2执行完以后,遇到同步线程,这时,将任务3加入异步的串行队列
278275
5. 又因为任务4比任务3早加入串行队列,所以,任务3要等待任务4完成以后,才能执行。但是任务3所在的同步线程会阻塞,所以任务4必须等任务3执行完以后再执行。这就又陷入了无限的等待中,造成死锁。
279276

280-
怎么样,是不是有点蒙逼,那快让我们进入第四小节吧!
281-
282-
##### 烧脑体操第四节
277+
##### 案例四
283278

284279
代码如下:
285280

286-
```
281+
```objectivec
287282
NSLog(@"1"); // 任务1
288283
dispatch_async(dispatch_get_global_queue(0, 0), ^{
289284
NSLog(@"2"); // 任务2
@@ -322,11 +317,11 @@ NSLog(@"5"); // 任务5
322317
323318
从以上的分析来看,得到的几个结果:1最先执行;2和5顺序不一定;4一定在3后面。
324319
325-
##### 烧脑体操第五节
320+
##### 案例五
326321
327-
什么?之前的你懂看懂了?那第五节估计也难不倒你咯,代码如下:
322+
代码如下:
328323
329-
```
324+
```objectivec
330325
dispatch_async(dispatch_get_global_queue(0, 0), ^{
331326
NSLog(@"1"); // 任务1
332327
dispatch_sync(dispatch_get_main_queue(), ^{
@@ -364,9 +359,9 @@ NSLog(@"5"); // 任务5
364359

365360
最终,只能得到1和4顺序不定的结果。
366361

367-
##### 烧脑体操总结
362+
##### 案例总结
368363

369-
相信对于绝大多数人来说,在烧脑体操第三节开始,是否死锁以及整个的执行流程就变得不是那么显而易见了,没错这五节烧脑体操就意在展示 GCD 的问题:如果想要设置线程间的依赖关系,那就需要嵌套,如果嵌套就会使得非常恶心的事情发生。这应该是 GCD 的一个非常明显的缺陷之一了。
364+
相信对于绝大多数人来说,在案例三开始,是否死锁以及整个的执行流程就变得不是那么显而易见了,这五个案例就意在展示 GCD 的问题:如果想要设置线程间的依赖关系,那就需要嵌套,如果嵌套就会导致一些复杂的事情发生。这应该是 GCD 的一个非常明显的缺陷之一了。
370365

371366
当然,NSOperation 为了我们提供了很方便设置依赖关系的解决方案。
372367

@@ -566,4 +561,5 @@ typedef enum : NSInteger {
566561
* http://www.humancode.us/2014/08/14/target-queues.html
567562
* http://www.dribin.org/dave/blog/archives/2009/05/05/concurrent_operations/
568563
* http://www.jianshu.com/p/0b0d9b1f1f19
569-
* http://www.cnblogs.com/tangbinblog/p/4133481.html
564+
* http://www.cnblogs.com/tangbinblog/p/4133481.html
565+
* http://www.saitjr.com/ios/ios-gcd-deadlock.html

source/iOS/Cocoa-Touch/Performance.md

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -43,14 +43,14 @@
4343

4444
### cornerRadius
4545

46-
```
47-
view.layer.cornerRadius = xxx
46+
```objectivec
47+
view.layer.cornerRadius = 6.0;
4848
view.layer.masksToBounds = YES;
4949
```
5050
这种方式会触发两次离屏渲染,如果在滚动页面中这么做的话就会遇到性能问题。当然我们可以进行缓存以优化性能,如下:
5151

52-
```
53-
view.layer.shouldRasterize = YES;
52+
```objectivec
53+
view.layer.shouldRasterize = YES;
5454
view.layer.rasterizationScale = [UIScreen mainScreen].scale;
5555
```
5656

@@ -60,7 +60,7 @@ shouldRasterize = YES 会使视图渲染内容被缓存起来,下次绘制的
6060

6161
### UIBezierPath
6262

63-
```
63+
```objectivec
6464
- (void)drawRect:(CGRect)rect {
6565
CGRect bounds = self.bounds;
6666
[[UIBezierPath bezierPathWithRoundedRect:rect cornerRadius:8.0] addClip];
@@ -116,7 +116,7 @@ extension UIView {
116116

117117
在调用时 只需要像这样写:
118118

119-
```
119+
```Swift
120120
let view = UIView(frame: CGRectMake(1,2,3,4))
121121
view.kt_addCorner(radius: 6)
122122
```
@@ -163,7 +163,7 @@ extension UIImageView {
163163

164164
在调用时只需要像如下这样写:
165165

166-
```
166+
```Swift
167167
let imageView = let imgView1 = UIImageView(image: UIImage(name: ""))
168168
imageView.kt_addCorner(radius: 6)
169169
```

0 commit comments

Comments
 (0)