又到了咱們每個月一次的活動日了。今天咱們仍是抽獎,送出 10 枚 MWeb for Mac 的兌換碼。MWeb 是一款專業的 Markdown 寫做、記筆記、靜態博客生成軟件,功能至關強大,相信用過的童鞋都知道。做者 oulvhai
,目前是獨立開發者。這裏感謝 oulvhai 爲咱們提供的兌換碼。html
MWeb 相關的介紹你們能夠查看官網,咱們此次的兌換碼是非 Mac App Store 版,還請中獎的小夥伴在官網下載試用版,而後激活便可。ios
關注公衆號在文章末尾抽獎web
上週公衆號發佈的如下文章:數組
本期知識小集的主要內容包括:bash
做者: halohilyapp
在項目中看到一段使用 GCD group 處理的代碼,簡化下來大概以下圖異步
dispatch_group_notify
的調用放在了 dispatch_group_async
的 block 中,乍一看會有是否產生永久阻塞的疑問,由於子任務完成後的派發任務被放在了一個子任務中。然而其實這是不會阻塞的,代碼會按編寫人的預期進行執行,即 log1 輸出以後,輸出 log2。這是由於 dispatch_group_notify 的 block 是異步執行的。async
再舉個例子,以下圖,執行結果依次會是:log 1,log 2 ,log 4 ,log 5 ,log 3。工具
雖然此處結果正確,但這種將 dispatch_group_notify 的調用放在某一個子任務的執行塊中的寫法是不被推薦的,它不但反邏輯,並且並不總能保證結果正確。好比若是在此例中,在調用了 dispatch_group_notify 的子任務以後,又爲該任務組使用 dispatch_group_async 語句添加後續子任務,這時代碼的執行結果是不肯定的。測試
既然最開始的例子中執行結果是正確的,有的同窗會問,若是把 dispatch_group_notify 的調用放在全部子任務的最前面,以下圖,是否也能得到預期的結果呢?答案是否認的,由於在最開始調用 dispatch_group_notify 時,子任務數量爲0,它的代碼塊會當即執行。然後爲該組派發了多個子任務,當這些子任務都執行完畢後,也並不會再次觸發 dispatch_group_notify 的代碼塊。
做者: Lefe_x
最近項目中遇到一個內存泄漏的問題,SecondViewController 這個類在 pop 後並無執行 dealloc 方法,也就沒有被正常被釋放。使用內存泄漏工具排查,並無發現有循環引用的地方,手動查了一下也沒發現異常。正在迷茫的時候,忽然看到了一個註冊監聽的地方。實現方式相似下面這樣:
- (void)dealloc {
[[Manager sharedInstance] removeObserver:self];
}
- (void)viewDidLoad {
[super viewDidLoad];
self.view.backgroundColor = [UIColor whiteColor];
[[Manager sharedInstance] addObserver:self];
}
複製代碼
看到這裏你應該已經猜到 SecondViewController 爲何沒被釋放,它被 Manager 持有了,而 Manager 是一個單例,天然 SecondViewController 也不會被釋放,dealloc 方法也不會執行。
這種設計很常見,每每給某個服務註冊監聽,達到相似通知的效果。若是使用數組保存監聽者,監聽者將會被數組持有。有同窗可能說,能夠在 viewDidAppear 註冊,在 viewWillDisappear 移除,這樣 SecondViewController 就會被釋放。可是,這樣設計很糟糕,咱們儘可能不去約束調用者如何調用某個 API。
其實正確的作法是使用一個弱引用容器,咱們可使用 NSHashTable 來保存監聽者,這樣當監聽者釋放後,將自動從 NSHashTable 中移除,也不須要主動調用移除監聽者的方法(也能夠調用,視狀況而定)。下面是一個簡單的實現,你也能夠參考 YYTextKeyboardManager 的實現:
_listenerTable = [NSHashTable weakObjectsHashTable];
- (void)addObserver:(NSObject *)obj {
[self.listenerTable addObject:obj];
}
- (void)removeObserver:(NSObject *)obj {
[self.listenerTable removeObject:obj];
}
複製代碼
做者: Vong_HUST
相信 UIAlertView
你們應該都很熟悉,可是最近遇到一個坑。
因爲歷史緣由,項目中還在大量使用 UIAlertView。某天測試過來反饋說,評論框字符長度超過最大長度時,點擊發送,彈出一個 alert
提示,點擊肯定後,評論框沒法在被激活,也就是無法彈出鍵盤了。非常怪異,debug
無果,搜了一下 stackoverflow
,發現有人遇到過相似的問題,能夠點擊末尾的參考連接來查看具體詳情。
他給出的解決方案就是把這種狀況下的 UIAlertView 換成 UIAlertController。試了下這種方式,果真是可行的,因爲以前 UIAlertView 是不依賴其它視圖層級的,建立後直接 show
就能夠了,因此不少地方直接寫在了非視圖控制器類中。在換成 UIAlertController 以後,因爲它是繼承自 UIViewController 的,因此必需要有 VC 把它 present
起來。解決方案也很簡單,寫一個 UIViewController 的分類獲取當前頂部可見的 ViewController,而後在上面 present
出 UIAlertController 便可,獲取頂部可見 ViewController 的代碼隨便一搜就能夠找到,這邊就不貼了。
PS:UIAlertController 是 iOS8 之後才提供的,不過相信你們也不用適配 iOS8 以前的系統了吧😂。若是還要適配,那就只能作版本區分了。。。
參考
iOS 9 - Keyboard pops up after UIAlertView dismissed
做者: 高老師很忙
iOS12提供了 Shortcuts
的功能,今天給你們介紹 2 個蘋果提供的提升 Shortcuts 調試效率的小技巧。
iPhone設置
->開發者
裏面提供了 Display Recent Shorts 和 Display Donations on Lock Screen 的開關,能夠忽略系統當前的建議和預測,顯示咱們須要調試的 Shortcuts;同時還支持 Force Sync Shortcuts to Watch 的功能,手動去強制同步到 Watch,會節省不少時間哦!我以爲這2個小技巧仍是很實用的,若是有其它小技巧歡迎一塊兒交流!
做者: KANGZUBIN
在平常開發中,咱們常常會在 Debug 模式下打斷點進行調試,並經過 LLDB 的 po
命令在控制檯打印一些變量的值,以方便排查問題。
今天在 Release 模式下編譯運行項目,發現要打印某一變量的值時(po xxx
),報以下錯誤:
error: Couldn't materialize: couldn't get the value of variable xxx: no location, value may have been optimized out
error: errored out in DoExecute, couldn't PrepareToExecuteJITExpression 複製代碼
大體意思是說,xxx
的值不存在,可能已經被編譯優化了。並且在斷點模式下當咱們把鼠標的箭頭移到某一變量上要進行快速瀏覽時,發現它們的值都是 nil
。
查了一下才發現,原來這與 Xcode 工程的編譯選項 Optimization Level
設置有關,它是指編譯器的優化級別,優化後的代碼效率比較高,可是可讀性比較差,且編譯時間更長,它有 6 個選項值以下圖:
上述每選項值的詳細說明能夠參考《Xcode 中 Optimization Level 的設置》和《如何加快編譯速度》兩篇文章,咱們這裏再也不贅述。
Xcode 工程的 Optimization Level 值在 Debug 模式下默認爲 None [-O0]
,表示編譯器不會嘗試優化代碼,保證調試時輸出指望的結果;而在 Release 模式下默認爲 Fastest, Smallest[-Os]
,表示編譯器將執行全部優化,且不會增長代碼的長度,它是可執行文件佔用更少內存的首選方案。
這也是爲何咱們在 Release 模式下斷點打印變量會報錯,由於編譯器已經給代碼作了優化,它將不在調試時記錄變量的值了。
此外,有時候遇到一些線上 Bug 可是在 Debug 調試時卻沒法復現,我猜有可能會跟編譯優化有關,你以爲呢?歡迎留言討論。
做者: 我是喬忘記瘋狂
Watch OS 4 新的 API,用於解決手腕轉動時手錶屏幕可能自動休眠的問題。好比在 watch 上展現二維碼給各類 POS 掃描,屏幕常常會自動休眠。經測支付寶 watch app 已經使用了此 API,不過官方推薦只針對某些特定界面打開此功能,而支付寶是整個 watch app 都打開了此功能。