From aafb6879593306b3adda42fbd8b5687e980bf8d5 Mon Sep 17 00:00:00 2001
From: iiiceblink <1248800415@qq.com>
Date: Thu, 28 Feb 2019 00:10:07 +0800
Subject: [PATCH] Update READ_cn.md
---
README_cn.md | 203 ++++++++++++++++++++++++++++-----------------------
1 file changed, 110 insertions(+), 93 deletions(-)
diff --git a/README_cn.md b/README_cn.md
index f4c2a48..617ded3 100644
--- a/README_cn.md
+++ b/README_cn.md
@@ -2,14 +2,15 @@
-这个库为Objective-C和Swift提供了协程功能。coobjc支持await、generator和actor model,接口参考了C#、Javascript和Kotlin中的很多设计。我们还提供了[cokit库](cokit/README.md)为Foundation和UIKit中的部分API提供了协程化支持,包括NSFileManager, JSON, NSData, UIImage等。coobjc也提供了元组的支持。
+这个库为 Objective-C 和 Swift 提供了协程功能。coobjc 支持 await、generator 和 actor model,接口参考了 C# 、Javascript 和 Kotlin 中的很多设计。我们还提供了[cokit库](cokit/README.md)为 Foundation 和 UIKit 中的部分 API 提供了协程化支持,包括 NSFileManager , JSON , NSData , UIImage 等。coobjc 也提供了元组的支持。
## 0x0 iOS异步编程问题
-基于Block的异步编程回调是目前iOS使用最广泛的异步编程方式,iOS系统提供的GCD库让异步开发变得很简单方便,但是基于这种编程方式的缺点也有很多,主要有以下几点:
+
+基于 Block 的异步编程回调是目前 iOS 使用最广泛的异步编程方式,iOS 系统提供的 GCD 库让异步开发变得很简单方便,但是基于这种编程方式的缺点也有很多,主要有以下几点:
* 容易进入"嵌套地狱"
* 错误处理复杂和冗长
-* 容易忘记调用completion handler
+* 容易忘记调用 completion handler
* 条件执行变得很困难
* 从互相独立的调用中组合返回结果变得极其困难
* 在错误的线程中继续执行
@@ -20,9 +21,10 @@
## 0x1 解决方案
-上述问题在很多系统和语言中都会遇到,解决问题的标准方式就是使用协程。这里不介绍太多的理论,简单说协程就是对基础函数的扩展,可以让函数异步执行的时候挂起然后返回值。协程可以用来实现generator,异步模型以及其他强大的能力。
-Kotlin是这两年由JetBrains推出的支持现代多平台应用的静态编程语言,支持JVM,Javascript,目前也可以在iOS上执行,这两年在开发者社区中也是比较火。
在Kotlin语言中基于协程的async/await,generator/yield等异步化技术都已经成了语法标配,Kotlin协程相关的介绍,大家可以参考:[https://www.kotlincn.net/docs/reference/coroutines/basics.html](https://www.kotlincn.net/docs/reference/coroutines/basics.html)
+上述问题在很多系统和语言中都会遇到,解决问题的标准方式就是使用协程。这里不介绍太多的理论,简单说协程就是对基础函数的扩展,可以让函数异步执行的时候挂起然后返回值。协程可以用来实现 generator ,异步模型以及其他强大的能力。
+
+Kotlin 是这两年由 JetBrains 推出的支持现代多平台应用的静态编程语言,支持 JVM ,Javascript ,目前也可以在 iOS 上执行,这两年在开发者社区中也是比较火。
在 Kotlin 语言中基于协程的 async/await ,generator/yield 等异步化技术都已经成了语法标配,Kotlin 协程相关的介绍,大家可以参考:[https://www.kotlincn.net/docs/reference/coroutines/basics.html](https://www.kotlincn.net/docs/reference/coroutines/basics.html)
## 0x2 协程
@@ -32,39 +34,42 @@ Kotlin是这两年由JetBrains推出的支持现代多平台应用的静态编
协程的概念在60年代就已经提出,目前在服务端中应用比较广泛,在高并发场景下使用极其合适,可以极大降低单机的线程数,提升单机的连接和处理能力,但是在移动研发中,iOS和android目前都不支持协程的使用
## 0x3 coobjc framework
-coobjc是由手机淘宝架构团队推出的能在iOS上使用的协程开发框架,目前支持Objective-C和Swift中使用,我们底层使用汇编和C语言进行开发,上层进行提供了Objective-C和Swift的接口,目前以Apache开源协议进行了开源.
-### 0x31 Install
+coobjc 是由手机淘宝架构团队推出的能在 iOS 上使用的协程开发框架,目前支持 Objective-C 和 Swift 中使用,我们底层使用汇编和 C 语言进行开发,上层进行提供了 Objective-C 和 Swift 的接口,目前以 Apache 开源协议进行了开源.
+
+### 0x31 安装
+
* cocoapods: pod 'coobjc'
-* source code: 所有代码在 ./coobjc 目录下
+* 源码安装: 所有代码在 ./coobjc 目录下
-### 0x32 Documents
-* Read the [协程框架设计](docs/arch_design.md) document.
-* Read the [coobjc Objective-C Guide](docs/usage.md) document.
-* Read the [coobjc Swift Guide](docs/usage_swift.md) document.
-* Read the [cokit framework](cokit/README.md) document, learn how to use the wrapper api of System Interface.
+### 0x32 文档
-### 0x33 Features
+* 阅读 [协程框架设计](docs/arch_design.md) 文档。
+* 阅读 [coobjc Objective-C Guide](docs/usage.md) 文档。
+* 阅读 [coobjc Swift Guide](docs/usage_swift.md) 文档。
+* 阅读 [cokit framework](cokit/README.md) 文档, 学习如何使用系统接口封装的 api 。
+
+### 0x33 特性
#### async/await
-* create coroutine
+* 创建协程
-使用co_launch方法创建协程
-```
+使用 `co_launch` 方法创建协程
+
+```objc
co_launch(^{
...
});
```
-co_launch创建的协程默认在当前线程进行调度
+`co_launch` 创建的协程默认在当前线程进行调度
-* await异步方法
+* await 异步方法
-在协程中我们使用await方法等待异步方法执行结束,得到异步执行结果
-
-```
+在协程中我们使用 await 方法等待异步方法执行结束,得到异步执行结果
+```objc
- (void)viewDidLoad{
...
co_launch(^{
@@ -75,12 +80,13 @@ co_launch创建的协程默认在当前线程进行调度
}
```
-上述代码将原本需要dispatch_async两次的代码变成了顺序执行,代码更加简洁
+上述代码将原本需要 `dispatch_async` 两次的代码变成了顺序执行,代码更加简洁
* 错误处理
-在协程中,我们所有的方法都是直接返回值的,并没有返回错误,我们在执行过程中的错误是通过co_getError()获取的,比如我们有以下从网络获取数据的接口,在失败的时候,promise会reject:error
-```
+在协程中,我们所有的方法都是直接返回值的,并没有返回错误,我们在执行过程中的错误是通过 `co_getError()` 获取的,比如我们有以下从网络获取数据的接口,在失败的时候, promise 会 `reject:error`
+
+```objc
- (CCOPromise*)co_GET:(NSString*)url
parameters:(NSDictionary*)parameters{
CCOPromise *promise = [CCOPromise promise];
@@ -95,7 +101,7 @@ co_launch创建的协程默认在当前线程进行调度
那我们在协程中可以如下使用:
-```
+```objc
co_launch(^{
id response = await([self co_GET:feedModel.feedUrl parameters:nil]);
if(co_getError()){
@@ -105,14 +111,13 @@ co_launch(^{
});
```
+#### 生成器
-#### Generator
+* 创建生成器
-* create generator
+我们使用 `co_sequence` 创建生成器
-我们使用co_sequence创建Generator
-
-```
+```objc
COCoroutine *co1 = co_sequence(^{
int index = 0;
while(co_isActive()){
@@ -122,9 +127,9 @@ COCoroutine *co1 = co_sequence(^{
});
```
-在其他协程中,我们可以调用next方法,获取生成器中的数据
+在其他协程中,我们可以调用 `next` 方法,获取生成器中的数据
-```
+```objc
co_launch(^{
for(int i = 0; i < 10; i++){
val = [[co1 next] intValue];
@@ -136,7 +141,7 @@ co_launch(^{
生成器可以在很多场景中进行使用,比如消息队列、批量下载文件、批量加载缓存等:
-```
+```objc
int unreadMessageCount = 10;
NSString *userId = @"xxx";
COSequence *messageSequence = sequenceOnBackgroundQueue(@"message_queue", ^{
@@ -156,30 +161,30 @@ co(^{
});
```
-通过生成器,我们可以把传统的生产者加载数据-》通知消费者模式,变成消费者需要数据-》告诉生产者加载模式,避免了在多线程计算中,需要使用很多共享变量进行状态同步,消除了在某些场景下对于锁的使用
-
+通过生成器,我们可以把传统的生产者加载数据->通知消费者模式,变成消费者需要数据->告诉生产者加载模式,避免了在多线程计算中,需要使用很多共享变量进行状态同步,消除了在某些场景下对于锁的使用
#### Actor
-> **_Actor的概念来自于Erlang,在AKKA中,可以认为一个Actor就是一个容器,用以存储状态、行为、Mailbox以及子Actor与Supervisor策略。Actor之间并不直接通信,而是通过Mail来互通有无。_**
-* create actor
+> **_ Actor 的概念来自于 Erlang ,在 AKKA 中,可以认为一个 Actor 就是一个容器,用以存储状态、行为、Mailbox 以及子 Actor 与 Supervisor 策略。Actor 之间并不直接通信,而是通过 Mail 来互通有无。_**
-我们可以使用co_actor_onqueue在指定线程创建actor
+* 创建 actor
-```
+我们可以使用 `co_actor_onqueue` 在指定线程创建 actor
+
+```objc
CCOActor *actor = co_actor_onqueue(^(CCOActorChan *channel) {
- ... //定义actor的状态变量
+ ... //定义 actor 的状态变量
for(CCOActorMessage *message in channel){
...//处理消息
}
}, q);
```
-* 给actor发送消息
+* 给 actor 发送消息
-actor的send方法可以给actor发送消息
+actor 的 `send` 方法可以给 actor 发送消息
-```
+```objc
CCOActor *actor = co_actor_onqueue(^(CCOActorChan *channel) {
... //定义actor的状态变量
for(CCOActorMessage *message in channel){
@@ -193,9 +198,11 @@ CCOActor *actor = co_actor_onqueue(^(CCOActorChan *channel) {
```
-#### tuple
-* create tuple
-使用co_tuple方法来创建元组
+#### 元组
+
+* 创建元组
+
+使用 `co_tuple` 方法来创建元组
```objc
COTuple *tup = co_tuple(nil, @10, @"abc");
@@ -203,10 +210,12 @@ NSAssert(tup[0] == nil, @"tup[0] is wrong");
NSAssert([tup[1] intValue] == 10, @"tup[1] is wrong");
NSAssert([tup[2] isEqualToString:@"abc"], @"tup[2] is wrong");
```
-可以在tuple中存储任何数据
-* unpack tuple
-可以使用co_unpack方法从tuple中取值
+可以在元组中存储任何数据
+
+* 元组取值
+
+可以使用 `co_unpack` 方法从元组中取值
```objc
id val0;
@@ -233,8 +242,9 @@ co_unpack(nil, nil, &str1) = co_tuple(nil, @10, @"abc");
NSAssert([str1 isEqualToString:@"abc"], @"str1 is wrong");
```
-* use tuple in coroutine
-first create a promise that resolve tuple value
+* 在协程中使用元组
+
+首先创建一个 promise 来处理元组里的值
```objc
COPromise*
@@ -252,9 +262,9 @@ cotest_loadContentFromFile(NSString *filePath){
}
```
-then you can fetch the value like this:
+然后,你可以像下面这样获取元组里的值:
-```
+```objc
co_launch(^{
NSString *tmpFilePath = nil;
NSData *data = nil;
@@ -265,12 +275,14 @@ co_launch(^{
XCTAssert(error == nil, @"error is wrong");
});
```
-use tuple you can get multiple values from await return
-#### Actual case using coobjc
-我们以GCDFetchFeed开源项目中Feeds流更新的代码为例,演示一下协程的实际使用场景和优势,下面是原始的不使用协程的实现:
+使用元组你可以从 `await` 返回值中获取多个值
-```
+#### 演示项目
+
+我们以 GCDFetchFeed 开源项目中 Feeds 流更新的代码为例,演示一下协程的实际使用场景和优势,下面是原始的不使用协程的实现:
+
+```objc
- (RACSignal *)fetchAllFeedWithModelArray:(NSMutableArray *)modelArray {
@weakify(self);
return [RACSignal createSignal:^RACDisposable *(id subscriber) {
@@ -304,9 +316,9 @@ use tuple you can get multiple values from await return
//通知单个完成
dispatch_group_leave(group);
}];
-
+
});//end dispatch async
-
+
} failure:^(NSURLSessionTask *operation, NSError *error) {
NSLog(@"Error: %@", error);
dispatch_async(fetchFeedQueue, ^{
@@ -316,12 +328,12 @@ use tuple you can get multiple values from await return
model.fid = [x integerValue];
dispatch_group_leave(group);
}];
-
+
});//end dispatch async
-
+
}];
-
- }//end for
+
+ } //end for
//全完成后执行事件
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
[subscriber sendCompleted];
@@ -331,9 +343,9 @@ use tuple you can get multiple values from await return
}
```
-下面是viewDidLoad中对上述方法的调用:
+下面是 `viewDidLoad` 中对上述方法的调用:
-```
+```objc
[UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
self.fetchingCount = 0; //统计抓取数量
@weakify(self);
@@ -376,7 +388,7 @@ use tuple you can get multiple values from await return
上述代码无论从可读性还是简洁性上都比较差,下面我们看一下使用协程改造以后的代码:
-```
+```objc
- (SMFeedModel*)co_fetchFeedModelWithUrl:(SMFeedModel*)feedModel{
feedModel.isSync = NO;
id response = await([self co_GET:feedModel.feedUrl parameters:nil]);
@@ -396,9 +408,9 @@ use tuple you can get multiple values from await return
}
```
-下面是viewDidLoad中使用协程调用该接口的地方:
+下面是 `viewDidLoad` 中使用协程调用该接口的地方:
-```
+```objc
co_launch(^{
for (NSUInteger index = 0; index < self.feeds.count; index++) {
SMFeedModel *model = self.feeds[index];
@@ -427,18 +439,20 @@ co_launch(^{
协程化改造之后的代码,变得更加简单易懂,不易出错
-#### Swift
-coobjc fully supports Swift through top-level encapsulation, enabling us to enjoy the coroutine ahead of time in Swift.
-Because Swift has richer and more advanced syntax support, coobjc is more elegant in Swift, for example:
+#### Swift
-```
+coobjc 通过上层封装来全面支持 Swift ,这使得我们可以提早在 Swift 中使用协程。
+
+由于 Swift 拥有更丰富和更高阶的语法支持,因而 coobjc 在 Swift 中的使用会更优雅,例如:
+
+```swift
func test() {
co_launch {//create coroutine
//fetch data asynchronous
let resultStr = try await(channel: co_fetchSomething())
print("result: \(resultStr)")
}
-
+
co_launch {//create coroutine
//fetch data asynchronous
let result = try await(promise: co_fetchSomethingAsynchronous())
@@ -454,47 +468,50 @@ func test() {
```
## 0x4 协程的优势
+
* 简明
* 概念少:只有很少的几个操作符,相比响应式几十个操作符,简直不能再简单了
* 原理简单: 协程的实现原理很简单,整个协程库只有几千行代码
* 易用
- * 使用简单:它的使用方式比GCD还要简单,接口很少
+ * 使用简单:它的使用方式比 GCD 还要简单,接口很少
* 改造方便:现有代码只需要进行很少的改动就可以协程化,同时我们针对系统库提供了大量协程化接口
* 清晰
* 同步写异步逻辑:同步顺序方式写代码是人类最容易接受的方式,这可以极大的减少出错的概率
- * 可读性高: 使用协程方式编写的代码比block嵌套写出来的代码可读性要高很多
+ * 可读性高: 使用协程方式编写的代码比 block 嵌套写出来的代码可读性要高很多
* 性能
* 调度性能更快:协程本身不需要进行内核级线程的切换,调度性能快,即使创建上万个协程也毫无压力
- * 减少卡顿卡死: 协程的使用以帮助开发减少锁、信号量的滥用,通过封装会引起阻塞的IO等协程接口,可以从根源上减少卡顿、卡死,提升应用整体的性能
+ * 减少卡顿卡死: 协程的使用以帮助开发减少锁、信号量的滥用,通过封装会引起阻塞的 IO 等协程接口,可以从根源上减少卡顿、卡死,提升应用整体的性能
## 0x5 交流
-* If you **need help**, use [Stack Overflow](http://stackoverflow.com/questions/tagged/coobjc). (Tag 'coobjc')
-* If you'd like to **ask a general question**, use [Stack Overflow](http://stackoverflow.com/questions/tagged/coobjc).
-* If you **found a bug**, _and can provide steps to reliably reproduce it_, open an issue.
-* If you **have a feature request**, open an issue.
-* If you **want to contribute**, submit a pull request.
+
+* 如果你**需要帮助**,请使用 [Stack Overflow](http://stackoverflow.com/questions/tagged/coobjc)。(标签为 'coobjc')
+* 如果你想**提问**,请使用 [Stack Overflow](http://stackoverflow.com/questions/tagged/coobjc)。
+* 如果你**发现了 bug**,并且可以提供可稳定复现的步骤,请开 issue。
+* 如果你有**新特性需求**,请开 issue。
+* 如果你**想贡献代码**,请提交 PR。
## 0x6 单元测试
+
coobjc includes a suite of unit tests within the Tests subdirectory. These tests can be run simply be executed the test action on the platform framework you would like to test.
-## 0x7 Credits
-coobjc couldn't exist without:
+## 0x7 致谢
-* [Promises](https://github.com/google/promises) - Google's Objective-C and Swift Promises framework.
-* [libtask](https://swtch.com/libtask/) - A simple coroutine library.
-* [movies](https://github.com/KMindeguia/movies) - a ios demo app, we use the code in coobjc examples
-* [v2ex](https://github.com/singro/v2ex) - An iOS client for v2ex.com, we use the code in coobjc examples
-* [tuples](https://github.com/atg/tuples) - Objective-C tuples.
+coobjc 离不开下面这些项目的帮助:
+
+* [Promises](https://github.com/google/promises) - Google 开发的 Objective-C 和 Swift 版本的 Promise 框架
+* [libtask](https://swtch.com/libtask/) - 一个简易的协程库
+* [movies](https://github.com/KMindeguia/movies) - 一个 iOS 演示项目,我们在 coobjc 的示例中使用了其中的代码
+* [v2ex](https://github.com/singro/v2ex) - v2ex.com 的 iOS 客户端项目,我们在 coobjc 的示例中使用了其中的代码
+* [tuples](https://github.com/atg/tuples) - Objective-C 元组
## 0x8 作者
+
* [pengyutang125](https://github.com/pengyutang125)
* [NianJi](https://github.com/NianJi)
* [intheway](https://github.com/intheway)
* [ValiantCat](https://github.com/ValiantCat)
* [jmpews](https://github.com/jmpews)
-## 0x9 License
-coobjc is released under the Apache 2.0 license. See [LICENSE](LICENSE) for details.
-
-
+## 0x9 协议
+coobjc 使用 Apache 2.0 协议,详情见 [LICENSE](LICENSE) 文件。