阿里妹導讀:剛剛,阿里巴巴正式對外開源了基于 Apache 2.0 協(xié)議的協(xié)程開發(fā)框架 coobjc,開發(fā)者們可以在 Github 上自主下載。
“專業(yè)、務實、高效、創(chuàng)新、把客戶的事當成自己的事”是我們每一個人一直以來堅持追求的企業(yè)文化。 創(chuàng)新互聯(lián)是您可以信賴的網站建設服務商、專業(yè)的互聯(lián)網服務提供商! 專注于成都網站設計、成都做網站、外貿網站建設、軟件開發(fā)、設計服務業(yè)務。我們始終堅持以客戶需求為導向,結合用戶體驗與視覺傳達,提供有針對性的項目解決方案,提供專業(yè)性的建議,創(chuàng)新互聯(lián)建站將不斷地超越自我,追逐市場,引領市場!
coobjc是為iOS平臺打造的開源協(xié)程開發(fā)框架,支持Objective-C和Swift,同時提供了cokit庫為Foundation和UIKit中的部分API提供了 協(xié)程 化支持,本文將為大家詳細介紹coobjc的設計理念及核心優(yōu)勢。
從2008年第一個iOS版本發(fā)布至今的11年時間里,iOS的異步編程方式發(fā)展緩慢。
基于 Block 的異步編程回調是目前 iOS 使用最廣泛的異步編程方式,iOS 系統(tǒng)提供的 GCD 庫讓異步開發(fā)變得很簡單方便,但是基于這種編程方式的缺點也有很多,主要有以下幾點:
針對多線程以及尤其引發(fā)的各種崩潰和性能問題,我們制定了很多編程規(guī)范、進行了各種新人培訓,嘗試降低問題發(fā)生的概率,但是問題依然很嚴峻,多線程引發(fā)的問題占比并沒有明顯的下降,異步編程本來就是很復雜的事情,單靠規(guī)范和培訓是難以從根本上解決問題的,需要有更加好的編程方式來解決。
上述問題在很多系統(tǒng)和語言開發(fā)中都可能會碰到,解決問題的標準方式就是使用協(xié)程,C#、Kotlin、Python、Javascript 等熱門語言均支持協(xié)程極其相關語法,使用這些語言的開發(fā)者可以很方便的使用協(xié)程及相關功能進行異步編程。
2017 年的 C++ 標準開始支持協(xié)程,Swift5 中也包含了協(xié)程相關的標準,從現在的發(fā)展趨勢看基于協(xié)程的全新的異步編程方式,是我們解決現有異步編程問題的有效的方式,但是蘋果基本已經不會升級 Objective-C 了,因此使用Objective-C的開發(fā)者是無法使用官方的協(xié)程能力的,而最新 Swift 的發(fā)布和推廣也還需要時日,為了讓廣大iOS開發(fā)者能快速享受到協(xié)程帶來的編程方式上的改變,手機淘寶架構團隊基于長期對系統(tǒng)底層庫和匯編的研究,通過匯編和C語言實現了支持 Objective-C 和 Swift 協(xié)程的完美解決方案 —— coobjc。
核心能力
內置系統(tǒng)擴展庫
coobjc設計
最底層是協(xié)程內核,包含了棧切換的管理、協(xié)程調度器的實現、協(xié)程間通信channel的實現等。
中間層是基于協(xié)程的操作符的包裝,目前支持async/await、Generator、Actor等編程模型。
最上層是對系統(tǒng)庫的協(xié)程化擴展,目前基本上覆蓋了Foundation和UIKit的所有IO和耗時方法。
核心實現原理
協(xié)程的核心思想是控制調用棧的主動讓出和恢復。一般的協(xié)程實現都會提供兩個重要的操作:
我們基于線程的代碼執(zhí)行時候,是沒法做出暫停操作的,我們現在要做的事情就是要代碼執(zhí)行能夠暫停,還能夠再恢復。 基本上代碼執(zhí)行都是一種基于調用棧的模型,所以如果我們能把當前調用棧上的狀態(tài)都保存下來,然后再能從緩存中恢復,那我們就能夠實現yield和 resume。
實現這樣操作有幾種方法呢?
上述第三種和第四種只是能過做到跳轉,但是沒法保存調用棧上的狀態(tài),看起來基本上不能算是實現了協(xié)程,只能算做做demo,第五種除非官方支持,否則自行改寫編譯器通用性很差。而第一種方案的 ucontext 在iOS上是廢棄了的,不能使用。那么我們使用的是第二種方案,自己用匯編模擬一下 ucontext。
模擬ucontext的核心是通過getContext和setContext實現保存和恢復調用棧。需要熟悉不同CPU架構下的調用約定(Calling Convention). 匯編實現就是要針對不同cpu實現一套,我們目前實現了 armv7、arm64、i386、x86_64,支持iPhone真機和模擬器。
說了這么多,還是看看代碼吧,我們從一個簡單的網絡請求加載圖片功能來看看coobjc到底是如何使用的。
下面是最普通的網絡請求的寫法:
下面是使用coobjc庫協(xié)程化改造后的代碼:
原本需要20行的代碼,通過coobjc協(xié)程化改造后,減少了一半,整個代碼邏輯和可讀性都更加好,這就是coobjc強大的能力,能把原本很復雜的異步代碼,通過協(xié)程化改造,轉變成邏輯簡潔的順序調用。
coobjc還有很多其他強大的能力,本文對于coobjc的實際使用就不過多介紹了,感興趣的朋友可以去官方github倉庫自行下載查看。
我們在iPhone7 iOS11.4.1的設備上使用協(xié)程和傳統(tǒng)多線程方式分別模擬高并發(fā)讀取數據的場景,下面是兩種方式得到的壓測數據。
從上面的表格我們可以看到使用在并發(fā)量很小的場景,由于多線程可以完全使用設備的計算核心,因此coobjc總耗時要比傳統(tǒng)多線程略高,但是由于整體耗時都很小,因此差異并不明顯,但是隨著并發(fā)量的增大,coobjc的優(yōu)勢開始逐漸體現出來,當并發(fā)量超過1000以后,傳統(tǒng)多線程開始出現線程分配異常,而導致很多并發(fā)任務并沒有執(zhí)行,因此在上表中顯示的是大于20秒,實際是任務已經無法正常執(zhí)行了,但是coobjc仍然可以正常運行。
我們在手機淘寶這種超級App中嘗試了協(xié)程化改造,針對部分性能差的頁面,我們發(fā)現在滑動過程中存在很多主線程IO調用、數據解析,導致幀率下降嚴重,通過引入coobjc,在不改變原有業(yè)務代碼的基礎上,通過全局hook部分IO、數據解析方法,即可讓原來在主線程中同步執(zhí)行的IO方法異步執(zhí)行,并且不影響原有的業(yè)務邏輯,通過測試驗證,這樣的改造在低端機(iPhone6及以下的機器)上的幀率有20%左右的提升。
簡明
易用
清晰
性能
程序是寫來給人讀的,只會偶爾讓機器執(zhí)行一下。——Abelson and Sussman
基于協(xié)程實現的編程范式能夠幫助開發(fā)者編寫出更加優(yōu)美、健壯、可讀性更強的代碼。
協(xié)程可以幫助我們在編寫并發(fā)代碼的過程中減少線程和鎖的使用,提升應用的性能和穩(wěn)定性。
本文作者:淘寶技術
sstoolkit 一套Category類型的庫,附帶很多自定義控件,功能不錯~
BlocksKit 將Block風格帶入UIKit和Founcation
cocoa-helpers 一些Cocoa的擴展 2年前的工程
CoconutKit 一系列擴展和一些自定組件
STUtils 一系列擴展包
PSFoundation 一系列擴展 和功能增強
ConciseKit 一系列宏定義 挺有意思
DTFoundation 又一系列擴展
BBBootstrap 一些常見功能的擴展庫
上一篇我們說到組件化開發(fā)是一個App最大一層的架構,那具體到了一個一個的業(yè)務組件里,比組件化開發(fā)小一點的架構就是三層架構。所謂三層架構就是指把項目中所有的類劃分到不同的層,目的是使項目邏輯更加清晰,提升開發(fā)和維護的效率,我們一般會把項目分為三層:數據層、業(yè)務層、視圖層。
注意:嚴格來講,三層架構并不真正就比組件化開發(fā)小,它們倆只是從不同的角度去做架構而已,往往是相互融合的,比如組件化開發(fā)里網絡庫就是三層架構里數據層的內容,UI庫就是三層架構里視圖層里的內容等,這里之所以說“三層架構是比組件化開發(fā)小一點的架構,主要是針對業(yè)務組件來說的”,當然甚至我們在不使用組件化開發(fā)時項目里依然可以使用三層架構。
比三層架構再小一點的架構就是視圖層架構,我們常說的MVC、MVVM都是?視圖層的架構。
MVC,即Model-View-Controller,它們的關系如下:
MVVM,即Model-View-ViewModel,它們的關系如下:
原文地址:
一、引言
? ? iOS10系統(tǒng)是一個較有突破性的系統(tǒng),其在Message,Notification等方面都開放了很多實用性的開發(fā)接口。本篇博客將主要探討iOS10中新引入的SpeechFramework框架。有個這個框架,開發(fā)者可以十分容易的為自己的App添加語音識別功能,不需要再依賴于其他第三方的語音識別服務,并且,Apple的Siri應用的強大也證明了Apple的語音服務是足夠強大的,不通過第三方,也大大增強了用戶的安全性。
二、SpeechFramework框架中的重要類
? ? SpeechFramework框架比較輕量級,其中的類并不十分冗雜,在學習SpeechFramework框架前,我們需要對其中類與類與類之間的關系有個大致的熟悉了解。
SFSpeechRecognizer:這個類是語音識別的操作類,用于語音識別用戶權限的申請,語言環(huán)境的設置,語音模式的設置以及向Apple服務發(fā)送語音識別的請求。
SFSpeechRecognitionTask:這個類是語音識別服務請求任務類,每一個語音識別請求都可以抽象為一個SFSpeechRecognitionTask實例,其中SFSpeechRecognitionTaskDelegate協(xié)議中約定了許多請求任務過程中的監(jiān)聽方法。
SFSpeechRecognitionRequest:語音識別請求類,需要通過其子類來進行實例化。
SFSpeechURLRecognitionRequest:通過音頻URL來創(chuàng)建語音識別請求。
SFSpeechAudioBufferRecognitionRequest:通過音頻流來創(chuàng)建語音識別請求。
SFSpeechRecognitionResult:語音識別請求結果類。
SFTranscription:語音轉換后的信息類。
SFTranscriptionSegment:語音轉換中的音頻節(jié)點類。
三、申請用戶語音識別權限與進行語音識別請求
? ? 開發(fā)者若要在自己的App中使用語音識別功能,需要獲取用戶的同意。首先需要在工程的Info.plist文件中添加一個Privacy-Speech Recognition Usage Description鍵,其實需要對應一個String類型的值,這個值將會在系統(tǒng)獲取權限的警告框中顯示,Info.plist文件如下圖所示:
使用SFSpeechRecognize類的requestAuthorization方法來進行用戶權限的申請,用戶的反饋結果會在這個方法的回調block中傳入,如下:
? //申請用戶語音識別權限
? [SFSpeechRecognizer requestAuthorization:^(SFSpeechRecognizerAuthorizationStatus status) {? ?
? }];
SFSpeechRecognizerAuthorzationStatus枚舉中定義了用戶的反饋結果,如下:
typedef NS_ENUM(NSInteger, SFSpeechRecognizerAuthorizationStatus) {
? ? //結果未知 用戶尚未進行選擇
? ? SFSpeechRecognizerAuthorizationStatusNotDetermined,
? ? //用戶拒絕授權語音識別
? ? SFSpeechRecognizerAuthorizationStatusDenied,
? ? //設備不支持語音識別功能
? ? SFSpeechRecognizerAuthorizationStatusRestricted,
? ? //用戶授權語音識別
? ? SFSpeechRecognizerAuthorizationStatusAuthorized,
};
如果申請用戶語音識別權限成功,開發(fā)者可以通過SFSpeechRecognizer操作類來進行語音識別請求,示例如下:
? ? //創(chuàng)建語音識別操作類對象
? ? SFSpeechRecognizer * rec = [[SFSpeechRecognizer alloc]init];
? ? //通過一個音頻路徑創(chuàng)建音頻識別請求
? ? SFSpeechRecognitionRequest * request = [[SFSpeechURLRecognitionRequest alloc]initWithURL:[[NSBundle mainBundle] URLForResource:@"7011" withExtension:@"m4a"]];
? ? //進行請求
? ? [rec recognitionTaskWithRequest:request resultHandler:^(SFSpeechRecognitionResult * _Nullable result, NSError * _Nullable error) {
? ? ? ? //打印語音識別的結果字符串
? ? ? ? NSLog(@"%@",result.bestTranscription.formattedString);
? ? }];
四、深入SFSpeechRecognizer類
SFSpeechRecognizer類的主要作用是申請權限,配置參數與進行語音識別請求。其中比較重要的屬性與方法如下:
//獲取當前用戶權限狀態(tài)
+ (SFSpeechRecognizerAuthorizationStatus)authorizationStatus;
//申請語音識別用戶權限
+ (void)requestAuthorization:(void(^)(SFSpeechRecognizerAuthorizationStatus status))handler;
//獲取所支持的所有語言環(huán)境
+ (NSSetNSLocale * *)supportedLocales;
//初始化方法 需要注意 這個初始化方法將默認以設備當前的語言環(huán)境作為語音識別的語言環(huán)境
- (nullable instancetype)init;
//初始化方法 設置一個特定的語言環(huán)境
- (nullable instancetype)initWithLocale:(NSLocale *)locale NS_DESIGNATED_INITIALIZER;
//語音識別是否可用
@property (nonatomic, readonly, getter=isAvailable) BOOL available;
//語音識別操作類協(xié)議代理
@property (nonatomic, weak) idSFSpeechRecognizerDelegate delegate;
//設置語音識別的配置參數 需要注意 在每個語音識別請求中也有這樣一個屬性 這里設置將作為默認值
//如果SFSpeechRecognitionRequest對象中也進行了設置 則會覆蓋這里的值
/*
typedef NS_ENUM(NSInteger, SFSpeechRecognitionTaskHint) {
? ? SFSpeechRecognitionTaskHintUnspecified = 0,? ? // 無定義
? ? SFSpeechRecognitionTaskHintDictation = 1,? ? ? // 正常的聽寫風格
? ? SFSpeechRecognitionTaskHintSearch = 2,? ? ? ? ? // 搜索風格
? ? SFSpeechRecognitionTaskHintConfirmation = 3,? ? // 短語風格
};
*/
@property (nonatomic) SFSpeechRecognitionTaskHint defaultTaskHint;
//使用回調Block的方式進行語音識別請求 請求結果會在Block中傳入
- (SFSpeechRecognitionTask *)recognitionTaskWithRequest:(SFSpeechRecognitionRequest *)request
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? resultHandler:(void (^)(SFSpeechRecognitionResult * __nullable result, NSError * __nullable error))resultHandler;
//使用代理回調的方式進行語音識別請求
- (SFSpeechRecognitionTask *)recognitionTaskWithRequest:(SFSpeechRecognitionRequest *)request
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? delegate:(id SFSpeechRecognitionTaskDelegate)delegate;
//設置請求所占用的任務隊列
@property (nonatomic, strong) NSOperationQueue *queue;
SFSpeechRecognizerDelegate協(xié)議中只約定了一個方法,如下:
//當語音識別操作可用性發(fā)生改變時會被調用
- (void)speechRecognizer:(SFSpeechRecognizer *)speechRecognizer availabilityDidChange:(BOOL)available;
? ? 通過Block回調的方式進行語音識別請求十分簡單,如果使用代理回調的方式,開發(fā)者需要實現SFSpeechRecognitionTaskDelegate協(xié)議中的相關方法,如下:
//當開始檢測音頻源中的語音時首先調用此方法
- (void)speechRecognitionDidDetectSpeech:(SFSpeechRecognitionTask *)task;
//當識別出一條可用的信息后 會調用
/*
需要注意,apple的語音識別服務會根據提供的音頻源識別出多個可能的結果 每有一條結果可用 都會調用此方法
*/
- (void)speechRecognitionTask:(SFSpeechRecognitionTask *)task didHypothesizeTranscription:(SFTranscription *)transcription;
//當識別完成所有可用的結果后調用
- (void)speechRecognitionTask:(SFSpeechRecognitionTask *)task didFinishRecognition:(SFSpeechRecognitionResult *)recognitionResult;
//當不再接受音頻輸入時調用 即開始處理語音識別任務時調用
- (void)speechRecognitionTaskFinishedReadingAudio:(SFSpeechRecognitionTask *)task;
//當語音識別任務被取消時調用
- (void)speechRecognitionTaskWasCancelled:(SFSpeechRecognitionTask *)task;
//語音識別任務完成時被調用
- (void)speechRecognitionTask:(SFSpeechRecognitionTask *)task didFinishSuccessfully:(BOOL)successfully;
SFSpeechRecognitionTask類中封裝了屬性和方法如下:
//此任務的當前狀態(tài)
/*
typedef NS_ENUM(NSInteger, SFSpeechRecognitionTaskState) {
SFSpeechRecognitionTaskStateStarting = 0,? ? ? // 任務開始
SFSpeechRecognitionTaskStateRunning = 1,? ? ? ? // 任務正在運行
SFSpeechRecognitionTaskStateFinishing = 2,? ? ? // 不在進行音頻讀入 即將返回識別結果
SFSpeechRecognitionTaskStateCanceling = 3,? ? ? // 任務取消
SFSpeechRecognitionTaskStateCompleted = 4,? ? ? // 所有結果返回完成
};
*/
@property (nonatomic, readonly) SFSpeechRecognitionTaskState state;
//音頻輸入是否完成
@property (nonatomic, readonly, getter=isFinishing) BOOL finishing;
//手動完成音頻輸入 不再接收音頻
- (void)finish;
//任務是否被取消
@property (nonatomic, readonly, getter=isCancelled) BOOL cancelled;
//手動取消任務
- (void)cancel;
關于音頻識別請求類,除了可以使用SFSpeechURLRecognitionRequest類來進行創(chuàng)建外,還可以使用SFSpeechAudioBufferRecognitionRequest類來進行創(chuàng)建:
@interface SFSpeechAudioBufferRecognitionRequest : SFSpeechRecognitionRequest
@property (nonatomic, readonly) AVAudioFormat *nativeAudioFormat;
//拼接音頻流
- (void)appendAudioPCMBuffer:(AVAudioPCMBuffer *)audioPCMBuffer;
- (void)appendAudioSampleBuffer:(CMSampleBufferRef)sampleBuffer;
//完成輸入
- (void)endAudio;
@end
五、語音識別結果類SFSpeechRecognitionResult
? ? SFSpeechRecognitionResult類是語音識別結果的封裝,其中包含了許多套平行的識別信息,其每一份識別信息都有可信度屬性來描述其準確程度。SFSpeechRecognitionResult類中屬性如下:
//識別到的多套語音轉換信息數組 其會按照準確度進行排序
@property (nonatomic, readonly, copy) NSArraySFTranscription * *transcriptions;
//準確性最高的識別實例
@property (nonatomic, readonly, copy) SFTranscription *bestTranscription;
//是否已經完成 如果YES 則所有所有識別信息都已經獲取完成
@property (nonatomic, readonly, getter=isFinal) BOOL final;
SFSpeechRecognitionResult類只是語音識別結果的一個封裝,真正的識別信息定義在SFTranscription類中,SFTranscription類中屬性如下:
//完整的語音識別準換后的文本信息字符串
@property (nonatomic, readonly, copy) NSString *formattedString;
//語音識別節(jié)點數組
@property (nonatomic, readonly, copy) NSArraySFTranscriptionSegment * *segments;
當對一句完整的話進行識別時,Apple的語音識別服務實際上會把這句語音拆分成若干個音頻節(jié)點,每個節(jié)點可能為一個單詞,SFTranscription類中的segments屬性就存放這些節(jié)點。SFTranscriptionSegment類中定義的屬性如下:
//當前節(jié)點識別后的文本信息
@property (nonatomic, readonly, copy) NSString *substring;
//當前節(jié)點識別后的文本信息在整體識別語句中的位置
@property (nonatomic, readonly) NSRange substringRange;
//當前節(jié)點的音頻時間戳
@property (nonatomic, readonly) NSTimeInterval timestamp;
//當前節(jié)點音頻的持續(xù)時間
@property (nonatomic, readonly) NSTimeInterval duration;
//可信度/準確度 0-1之間
@property (nonatomic, readonly) float confidence;
//關于此節(jié)點的其他可能的識別結果
@property (nonatomic, readonly) NSArrayNSString * *alternativeSubstrings;
溫馨提示:SpeechFramework框架在模擬器上運行會出現異常情況,無法進行語音識別請求。會報出kAFAssistantErrorDomain的錯誤,還望有知道解決方案的朋友,給些建議,Thanks。
cocoa與cocoa Touch區(qū)別之分 相同之處:兩者都包含OC運行時的兩個核心框架: cocoa包含Foundation和AppKit框架,可用于開發(fā)Mac OS X系統(tǒng)的應用程序 cocoa touch包含Foundation和UIKit框架,可用于開發(fā)iPhone OS 系統(tǒng)的應用程序 Cocoa時Mac OS X...
當前題目:ios的開發(fā)框架,ios開發(fā)常用框架
當前URL:http://chinadenli.net/article12/dsdeodc.html
成都網站建設公司_創(chuàng)新互聯(lián),為您提供電子商務、云服務器、品牌網站建設、網站營銷、微信小程序、品牌網站設計
聲明:本網站發(fā)布的內容(圖片、視頻和文字)以用戶投稿、用戶轉載內容為主,如果涉及侵權請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內容未經允許不得轉載,或轉載時需注明來源: 創(chuàng)新互聯(lián)