资料介绍
软件简介
coobjc 为 Objective-C 和 Swift 提供了协程功能。coobjc 支持 await、generator 和 actor model,接口参考了 C# 、Javascript 和 Kotlin 中的很多设计。我们还提供了 cokit 库为 Foundation 和 UIKit 中的部分 API 提供了协程化支持,包括 NSFileManager、JSON、NSData 与 UIImage 等。coobjc 也提供了元组的支持。
0x0 iOS 异步编程问题
基于 Block 的异步编程回调是目前 iOS 使用最广泛的异步编程方式,iOS 系统提供的 GCD 库让异步开发变得很简单方便,但是基于这种编程方式的缺点也有很多,主要有以下几点:
- 容易进入"嵌套地狱"
- 错误处理复杂和冗长
- 容易忘记调用 completion handler
- 条件执行变得很困难
- 从互相独立的调用中组合返回结果变得极其困难
- 在错误的线程中继续执行
- 难以定位原因的多线程崩溃
- 锁和信号量滥用带来的卡顿、卡死
上述问题反应到线上应用本身就会出现大量的多线程崩溃。
0x1 解决方案
上述问题在很多系统和语言中都会遇到,解决问题的标准方式就是使用协程。这里不介绍太多的理论,简单说协程就是对基础函数的扩展,可以让函数异步执行的时候挂起然后返回值。协程可以用来实现 generator ,异步模型以及其他强大的能力。
Kotlin 是这两年由 JetBrains 推出的支持现代多平台应用的静态编程语言,支持 JVM ,Javascript ,目前也可以在 iOS 上执行,这两年在开发者社区中也是比较火。
在 Kotlin 语言中基于协程的 async/await ,generator/yield 等异步化威廉希尔官方网站 都已经成了语法标配,Kotlin 协程相关的介绍,大家可以参考:https://www.kotlincn.net/docs/reference/coroutines/basics.html
0x2 协程
协程是一种在非抢占式多任务场景下生成可以在特定位置挂起和恢复执行入口的程序组件
协程的概念在60年代就已经提出,目前在服务端中应用比较广泛,在高并发场景下使用极其合适,可以极大降低单机的线程数,提升单机的连接和处理能力,但是在移动研发中,iOS和android目前都不支持协程的使用
0x3 coobjc 框架
coobjc 是由手机淘宝架构团队推出的能在 iOS 上使用的协程开发框架,目前支持 Objective-C 和 Swift 中使用,我们底层使用汇编和 C 语言进行开发,上层进行提供了 Objective-C 和 Swift 的接口,目前以 Apache 开源协议进行了开源。
0x31 安装
- cocoapods 安装: pod 'coobjc'
- 源码安装: 所有代码在 ./coobjc 目录下
0x32 文档
- 阅读 协程框架设计 文档。
- 阅读 coobjc Objective-C Guide 文档。
- 阅读 coobjc Swift Guide 文档。
- 阅读 cokit framework 文档, 学习如何使用系统接口封装的 api 。
0x33 特性
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
- (CCOPromise*)co_GET:(NSString*)url parameters:(NSDictionary*)parameters{ CCOPromise *promise = [CCOPromise 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]); } } });
通过生成器,我们可以把传统的生产者加载数据->通知消费者模式,变成消费者需要数据->告诉生产者加载模式,避免了在多线程计算中,需要使用很多共享变量进行状态同步,消除了在某些场景下对于锁的使用
Actor
_ Actor 的概念来自于 Erlang ,在 AKKA 中,可以认为一个 Actor 就是一个容器,用以存储状态、行为、Mailbox 以及子 Actor 与 Supervisor 策略。Actor 之间并不直接通信,而是通过 Mail 来互通有无。_
- 创建 actor
我们可以使用 co_actor_onqueue
在指定线程创建 actor
CCOActor *actor = co_actor_onqueue(^(CCOActorChan *channel) { ... //定义 actor 的状态变量 for(CCOActorMessage *message in channel){ ...//处理消息 } }, q);
- 给 actor 发送消息
actor 的 send
方法可以给 actor 发送消息
CCOActor *actor = co_actor_onqueue(^(CCOActorChan *channel) { ... //定义actor的状态变量 for(CCOActorMessage *message in channel){ ...//处理消息 } }, q); // 给actor发送消息 [actor send:@"sadf"]; [actor send:@(1)];
元组
- 创建元组
使用 co_tuple
方法来创建元组
COTuple *tup = co_tuple(nil, @10, @"abc"); 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");
可以在元组中存储任何数据
- 元组取值
可以使用 co_unpack
方法从元组中取值
id val0; NSNumber *number = nil; NSString *str = nil; co_unpack(&val0, &number, &str) = co_tuple(nil, @10, @"abc"); NSAssert(val0 == nil, @"val0 is wrong"); NSAssert([number intValue] == 10, @"number is wrong"); NSAssert([str isEqualToString:@"abc"], @"str is wrong"); co_unpack(&val0, &number, &str) = co_tuple(nil, @10, @"abc", @10, @"abc"); NSAssert(val0 == nil, @"val0 is wrong"); NSAssert([number intValue] == 10, @"number is wrong"); NSAssert([str isEqualToString:@"abc"], @"str is wrong"); co_unpack(&val0, &number, &str, &number, &str) = co_tuple(nil, @10, @"abc"); NSAssert(val0 == nil, @"val0 is wrong"); NSAssert([number intValue] == 10, @"number is wrong"); NSAssert([str isEqualToString:@"abc"], @"str is wrong"); NSString *str1; co_unpack(nil, nil, &str1) = co_tuple(nil, @10, @"abc"); NSAssert([str1 isEqualToString:@"abc"], @"str1 is wrong");
- 在协程中使用元组
首先创建一个 promise 来处理元组里的值
COPromise* cotest_loadContentFromFile(NSString *filePath){ return [COPromise promise:^(COPromiseFullfill _Nonnull resolve, COPromiseReject _Nonnull reject) { if ([[NSFileManager defaultManager] fileExistsAtPath:filePath]) { NSData *data = [[NSData alloc] initWithContentsOfFile:filePath]; resolve(co_tuple(filePath, data, nil)); } else{ NSError *error = [NSError errorWithDomain:@"fileNotFound" code:-1 userInfo:nil]; resolve(co_tuple(filePath, nil, error)); } }]; }
然后,你可以像下面这样获取元组里的值:
co_launch(^{ NSString *tmpFilePath = nil; NSData *data = nil; NSError *error = nil; co_unpack(&tmpFilePath, &data, &error) = await(cotest_loadContentFromFile(filePath)); XCTAssert([tmpFilePath isEqualToString:filePath], @"file path is wrong"); XCTAssert(data.length > 0, @"data is wrong"); XCTAssert(error == nil, @"error is wrong"); });
使用元组你可以从 await
返回值中获取多个值。
- ChatGPT:AI模型框架研究 1次下载
- 【前端开发】一篇文章概括目前流行的前端开发框架
- 苹果ios蓝牙调试助手工具源代码下载 7次下载
- Linux内核开发框架学习资料汇总 24次下载
- ThinkPHP 6.0完全开发手册资源下载 13次下载
- 基于AADL的自主无人系统可成长框架综述 3次下载
- 一种基于框架特征的共指消解方法 7次下载
- 什么是框架?MATLAB的单元测试框架中文版资料详细概述 0次下载
- 如何从一名iOS开发新手到iOS开发专家详细建议分析 2次下载
- IOS开发教程之ob<x>jective-C的十个面试题和解答资料免费下载 0次下载
- Java Web开发教程之Spring框架入门详细资料免费下载 14次下载
- AN1292与电机控制应用程序框架对比 2次下载
- SSM框架在Web应用开发中的设计与实现 pdf下载 2次下载
- android框架与应用开发介绍 7次下载
- 基于Struts框架和Procedure的Web开发模式
- 谈谈协程的那些事儿 1010次阅读
- 详解Linux线程、线程与异步编程、协程与异步 835次阅读
- 使用platformio平台和Arduino框架开发STM32G0 3012次阅读
- 聊聊PHP的web应用程序开发框架存在的漏洞有哪些 1561次阅读
- 使用channel控制协程数量 1036次阅读
- HDF驱动框架中USB DDK的解析与开发指导 2000次阅读
- 方舟开发框架中容器类的各种类型 1437次阅读
- 华为推出新声明式 UI 开发框架(ArkUI) 4037次阅读
- 现在流行的Web APP开发框架有哪些 1.1w次阅读
- 区块链应用开发框架Forge介绍 2226次阅读
- 协处理器的介绍及应用 3859次阅读
- 手机上的协处理器有什么作用_苹果协处理器是干什么的 2.1w次阅读
- Python自动化运维之协程函数赋值过程 3655次阅读
- HBase的协处理器开发编码实例 1824次阅读
- Python中的多核CPU共享数据之协程详解 6452次阅读
下载排行
本周
- 1山景DSP芯片AP8248A2数据手册
- 1.06 MB | 532次下载 | 免费
- 2RK3399完整板原理图(支持平板,盒子VR)
- 3.28 MB | 339次下载 | 免费
- 3TC358743XBG评估板参考手册
- 1.36 MB | 330次下载 | 免费
- 4DFM软件使用教程
- 0.84 MB | 295次下载 | 免费
- 5元宇宙深度解析—未来的未来-风口还是泡沫
- 6.40 MB | 227次下载 | 免费
- 6迪文DGUS开发指南
- 31.67 MB | 194次下载 | 免费
- 7元宇宙底层硬件系列报告
- 13.42 MB | 182次下载 | 免费
- 8FP5207XR-G1中文应用手册
- 1.09 MB | 178次下载 | 免费
本月
- 1OrCAD10.5下载OrCAD10.5中文版软件
- 0.00 MB | 234315次下载 | 免费
- 2555集成电路应用800例(新编版)
- 0.00 MB | 33566次下载 | 免费
- 3接口电路图大全
- 未知 | 30323次下载 | 免费
- 4开关电源设计实例指南
- 未知 | 21549次下载 | 免费
- 5电气工程师手册免费下载(新编第二版pdf电子书)
- 0.00 MB | 15349次下载 | 免费
- 6数字电路基础pdf(下载)
- 未知 | 13750次下载 | 免费
- 7电子制作实例集锦 下载
- 未知 | 8113次下载 | 免费
- 8《LED驱动电路设计》 温德尔著
- 0.00 MB | 6656次下载 | 免费
总榜
- 1matlab软件下载入口
- 未知 | 935054次下载 | 免费
- 2protel99se软件下载(可英文版转中文版)
- 78.1 MB | 537798次下载 | 免费
- 3MATLAB 7.1 下载 (含软件介绍)
- 未知 | 420027次下载 | 免费
- 4OrCAD10.5下载OrCAD10.5中文版软件
- 0.00 MB | 234315次下载 | 免费
- 5Altium DXP2002下载入口
- 未知 | 233046次下载 | 免费
- 6电路仿真软件multisim 10.0免费下载
- 340992 | 191187次下载 | 免费
- 7十天学会AVR单片机与C语言视频教程 下载
- 158M | 183279次下载 | 免费
- 8proe5.0野火版下载(中文版免费下载)
- 未知 | 138040次下载 | 免费
评论
查看更多