還在用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,還有很多新特性,歡迎一起學習和討論。


分享到:


相關文章: