「 iOS知識小集 」2018 · 第 36 期

知識小集發表於2018-11-13

原文連結

上週公眾號釋出的以下文章:

本期知識小集的主要內容包括:

  • 使用 Audio Queue 進行流式錄音
  • JSON 格式化顯示
  • Xcode 10 檔案無法關聯的 bug

使用 Audio Queue 進行流式錄音

作者: halohily

在 iOS 中錄音的需求很常見,對於大多數場景採用系統提供的 AVAudioRecorder。指定一個音訊檔案儲存路徑,即可開啟錄音。然而,這樣我們只能在錄音結束之後獲得音訊資料,無法實時進行。訊飛輸入法的 ASR SDK 中提供了一個寫入音訊 data 的介面,就是期望我們自己採用流式錄音,錄音過程中可以實時獲得音訊資料,從而接連不斷地傳遞給訊飛的 SDK。

對於流式錄音,這裡推薦使用 Audio Queue 實現。它同樣是官方提供的元件,只不過相對於 AVFoundation 更底層一些。使用它錄音,首先初始化一個音訊佇列 AudioQueue,然後是三個 buffer,用來儲存流式錄音過程中的每一幀音訊 data。注意,通過 buffer 大小的不同設定,即可實現每一幀時長的控制。最後,即是實現每一幀完成後的回撥函式,在這個函式中完成音訊資料的實時傳遞。

相反的,它同樣支援音訊的流式播放。除此之外,它還可以滿足對音訊編碼的不同需求。

參考資料

Audio Queue Services

JSON 格式化顯示

作者: Lefe_x

有時候我們想檢視網路請求的內容,我們往往看到的結果是(格式非常混亂):

{"status":{"msg":"success","code":0},"data":{"book_info":[{"doc_id":"a4bdba4cf7ec4afe04a1df7c1","author":"Lefe_x","is_white_book":0,"rec_tag":"熱門推薦","small_cover_url":"http:\/\/a3.att.hudong.com\/42\/58\/01300000820274128088583100471.jpg","rec_reason":"十分好看","book_title":"孩子你慢慢來"},{"doc_id":"a4bdba4cf7ec4afe04a1df7c3","author":"林語堂","is_white_book":0,"rec_tag":"","small_cover_url":"http:\/\/image.hexun.com\/book\/upload\/2013\/03\/07\/153148_20_c.jpg","rec_reason":"容易理解","book_title":"親愛的安德烈"}]}}
複製程式碼

上面這中方式,看起來非常不友好。如果能夠顯示成下圖的格式,是不是很爽?我們來看看具體的實現。

「 iOS知識小集 」2018 · 第 36 期

想實現上面的效果,可以使用 JS 中的 JSON.parseJSON.stringify 方法對 json 字串轉換,把轉換後的結果使用 UITextView 或者 UILabel 顯示出來即可。使用 UITextView 的好處是,內容太長直接可以滾動。圖中的實現方式是使用的 WKWebView,目的是給 Json 高亮(高亮程式碼可以參考 highlight.min.js)。

iOS 中呼叫 JS 中的方法我們在知識小集的《一本走心的JS-NA 互動電子書》上有很詳細的講解,還不會 JS-NA 互動的朋友可以在知識小集公眾號輸入 jn 即可免費獲得。

把用到的 JS 方法定義到一個 JS 檔案中,命名為 json_parse.js

function parseJson(string) {
	try {
		return JSON.parse(string);
	} catch (error) {
		return null;
	}
}

function renderJson(json) {
	return JSON.stringify(json, null, 2);
}
複製程式碼

iOS 端的程式碼如下:

NSString *json = @"iOS中的json字串";
NSString *filePath = [[NSBundle mainBundle] pathForResource:@"json_parse" ofType:@"js"];
NSString *js = [NSString stringWithContentsOfFile:filePath encoding:NSUTF8StringEncoding error:nil];
// 使用 JSContext 載入 JS 檔案
[self.context evaluateScript:js withSourceURL:[NSURL URLWithString:@"json_parse.js"]];
// 呼叫 parseJson 方法
JSValue *parseJsonResultValue = [self.context[@"parseJson"] callWithArguments:@[json]]; 
// 呼叫 renderJson 方法
JSValue *renderJsonResultValue = [self.context[@"renderJson"] callWithArguments:@[[parseJsonResultValue toObject] ?: @""]];
// renderJson 就是我們最終要顯示的字串
NSString *renderJson = [renderJsonResultValue toString];
複製程式碼

有時候在 iOS 中實現不了的需求,可以想著用 JS 來實現,我覺得這是 iOS 與 JS 互動的奧妙之處。

Xcode 10 檔案無法關聯的 bug

作者: Vong_HUST

今天分享一個最近使用 Xcode 遇到的一個坑。相信大家在寫(或者看開源庫)一些類,都會有一個匹配的 XXX+Private.hXXX+Subclass.h 這種標頭檔案,裡面專門用來放主類的 Extension,主要用途是為了讓某些屬性和方法模組內“僅模組內(或子類)可見”,這裡之所以加雙引號是因為在 Objective-C 中所有的公共標頭檔案在任何類中都能被 import 到,所以這裡的標頭檔案僅從命名上做一個隔離。Class Extension 的建立也很簡單,新建檔案,然後選擇 Objective-C File,下一步 type 選 Extension 即可。確認後 Xcode 會自動生成一個 YourClass+XXX.h 的檔案(XXX 為你新建檔案時輸入的內容)。但是此時如果使用快捷鍵(command+ctrl+↑/↓),發現無法和主類關聯,即無法跳轉到主類的 .h/.m。

這就很難受了,之前版本 Xcode 都是可以的,具體從哪個版本開始不能關聯沒有去關心,只關心如何解決。恰好最近有看 IGListKit 的相關程式碼,發現裡面也大量使用了這種方式,但是它的 Extension 標頭檔案名都是類似 XXXInternal.h(比如 IGListAdapterInternal.h)這種,而且它是能夠使用快捷鍵在主類和 Extension 之間跳轉的,難道是檔名的原因導致的?後面手動把 YourClass+XXX.h 改名為 YourClassXXX.h,然後發現還是不行。但是 build 一下之後,又能像從前那樣使用快捷鍵愉快地在檔案間切換了。不過值得一提的是,能用快捷鍵跳轉的僅 XXXX+Private.h 可行(同事的實踐),其餘的目前試過的都不行。這鍋不知道該不該 Xcode 背。

最後如果你也和我有一樣的困擾,可以嘗試去除檔名中的+號,雖然麻煩了一點,但至少能用了?。

關注我們

歡迎關注我們的公眾號:iOS-Tips,也歡迎加入我們的群組討論問題。可以公眾號留言 iosflutter 等關鍵詞獲取入群方式。

「 iOS知識小集 」2018 · 第 36 期

相關文章