还在用Objective-C,那么你有福了

吐槽

mac系开发人员一直以来对于Objective-C有很多抱怨,虽然目前swift已经快发布5.0版本了,但是还是不少开发者还在使用Objective-C,那么今天你有福了

推荐

coobjc 来了,阿里出品,必属精品!!

地址:https://github.com/alibaba/coobjc

介绍


还在用Objective-C,那么你有福了


这个库为 Objective-C 和 Swift 提供了协程功能。coobjc 支持 await、generator 和 actor model,接口参考了 C# 、Javascript 和 Kotlin 中的很多设计。我们还提供了 cokit 库为 Foundation 和 UIKit 中的部分 API 提供了协程化支持,包括 NSFileManager , JSON , NSData , UIImage 等。coobjc 也提供了元组的支持。

干嘛的

  • iOS 异步编程问题

基于 Block 的异步编程回调是目前 iOS 使用最广泛的异步编程方式,iOS 系统提供的 GCD 库让异步开发变得很简单方便,但是基于这种编程方式的缺点也有很多,主要有以下几点:

  1. 容易进入"嵌套地狱"
  2. 错误处理复杂和冗长
  3. 容易忘记调用 completion handler
  4. 条件执行变得很困难
  5. 从互相独立的调用中组合返回结果变得极其困难
  6. 在错误的线程中继续执行
  7. 难以定位原因的多线程崩溃
  8. 锁和信号量滥用带来的卡顿、卡死

上述问题反应到线上应用本身就会出现大量的多线程崩溃

  • 解决方案

上述问题在很多系统和语言中都会遇到,解决问题的标准方式就是使用协程。这里不介绍太多的理论,简单说协程就是对基础函数的扩展,可以让函数异步执行的时候挂起然后返回值。协程可以用来实现 generator ,异步模型以及其他强大的能力。

Kotlin 是这两年由 JetBrains 推出的支持现代多平台应用的静态编程语言,支持 JVM ,Javascript ,目前也可以在 iOS 上执行,这两年在开发者社区中也是比较火。

  • 协程

协程是一种在非抢占式多任务场景下生成可以在特定位置挂起和恢复执行入口的程序组件

协程的概念在60年代就已经提出,目前在服务端中应用比较广泛,在高并发场景下使用极其合适,可以极大降低单机的线程数,提升单机的连接和处理能力,但是在移动研发中,iOS和android目前都不支持协程的使用

  • coobjc 框架

coobjc 是由手机淘宝架构团队推出的能在 iOS 上使用的协程开发框架,目前支持 Objective-C 和 Swift 中使用,我们底层使用汇编和 C 语言进行开发,上层进行提供了 Objective-C 和 Swift 的接口,目前以 Apache 开源协议进行了开源。

  • 特性

async/await

  • 创建协程

使用 co_launch 方法创建协程

co_launch(^{
...
});

co_launch 创建的协程默认在当前线程进行调度

  • await 异步方法

在协程中我们使用 await 方法等待异步方法执行结束,得到异步执行结果

- (void)viewDidLoad{
...
co_launch(^{
NSData *data = await(downloadDataFromUrl(url));

UIImage *image = await(imageFromData(data));
self.imageView.image = image;
});
}

上述代码将原本需要 dispatch_async 两次的代码变成了顺序执行,代码更加简洁

  • 错误处理

在协程中,我们所有的方法都是直接返回值的,并没有返回错误,我们在执行过程中的错误是通过 co_getError() 获取的,比如我们有以下从网络获取数据的接口,在失败的时候, promise 会 reject:error

- (COPromise*)co_GET:(NSString*)url
parameters:(NSDictionary*)parameters{
COPromise *promise = [COPromise promise];
[self GET:url parameters:parameters progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {
[promise fulfill:responseObject];
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
[promise reject:error];
}];
return promise;
}

那我们在协程中可以如下使用:

co_launch(^{
id response = await([self co_GET:feedModel.feedUrl parameters:nil]);
if(co_getError()){
//处理错误信息
}
...
});

生成器

  • 创建生成器

我们使用 co_sequence 创建生成器

COCoroutine *co1 = co_sequence(^{
int index = 0;
while(co_isActive()){
yield_val(@(index));
index++;
}
});

在其他协程中,我们可以调用 next 方法,获取生成器中的数据

co_launch(^{
for(int i = 0; i < 10; i++){
val = [[co1 next] intValue];
}
});
  • 使用场景

生成器可以在很多场景中进行使用,比如消息队列、批量下载文件、批量加载缓存等:

int unreadMessageCount = 10;
NSString *userId = @"xxx";
COSequence *messageSequence = sequenceOnBackgroundQueue(@"message_queue", ^{
//在后台线程执行
while(1){
yield(queryOneNewMessageForUserWithId(userId));
}
});
//主线程更新UI
co(^{

for(int i = 0; i < unreadMessageCount; i++){
if(!isQuitCurrentView()){
displayMessage([messageSequence take]);
}
}
});

通过生成器,我们可以把传统的生产者加载数据->通知消费者模式,变成消费者需要数据->告诉生产者加载模式,避免了在多线程计算中,需要使用很多共享变量进行状态同步,消除了在某些场景下对于锁的使用

最后

coobjc支持Objective-C和swift,还有很多新特性,欢迎一起学习和讨论。


分享到:


相關文章: