
iOS摸魚周報,主要分享大家開發過程遇到的經驗教訓及學習内容。成立的目的一個是開發知識碎片化,需要有一個地方去總結并用于回顧;另一個是為了提醒自己不斷學習,内卷日益嚴重的開發環境下,不進則退。
雖說是周報,但目前内容的貢獻途徑還未穩定下來,如果後續的内容不足一期,可能會拖更到下一周再發。是以希望大家可以多分享自己學到的開發小技巧和解bug遭遇。
周報倉庫在這裡:https://github.com/zhangferry/iOSWeeklyLearning,可以檢視README了解貢獻方式;另可關注公衆号:iOS成長之路,背景點選進群交流,聯系我們。
開發Tips
開發小技巧收錄。
幾個有用的git指令
覆寫最近一次commit
當我們開發完一部分功能時,會送出commit,如果這時發現對應的功能少改了一些東西,我們可以單獨提一個commit标記這個小改動,但更推薦的做法是将這兩次改動合并為同一個,對應的指令是:
$ git commit --amend -m "message"
合并多個commit
如果想将已經生成的多個commit進行合并,可以使用:
$ git rebase -i [startpoint] [endpoint]
$ git rebase -i HEAD~2 # 合并最近兩次送出
endpoint預設為目前分支指向的HEAD節點。參數-i表示interactive(互動),該指令執行之後會進入一個vim的互動編輯界面,下面會有一些參數的說明:
pick:保留該commit(縮寫:p)
reword:保留該commit,但我需要修改該commit的注釋(縮寫:r)
edit:保留該commit, 但我要停下來修改該送出(不僅僅修改注釋)(縮寫:e)
squash:将該commit和前一個commit合并(縮寫:s)
fixup:将該commit和前一個commit合并,但我不要保留該送出的注釋資訊(縮寫:f)
exec:執行shell指令(縮寫:x)
drop:我要丢棄該commit(縮寫:d)
永久删除git内二進制
如果我們開發中忘了把某二進制檔案加入
.gitignore
,而放入了git檔案,那它就會一直存在。比如Pod目錄,當引入很多庫時,git檔案會越來越大,即使後面再加入到
.gitignore
,git曆史裡也會存有記錄,這個是無法删除的。好在git給我們提供了一個補救措施:
git filter-branch --tree-filter 'rm -f target.file'
後面的指令裡可以執行删除語句。注意該指令會重寫整個git曆史,多人協作時更應該慎用。
git倉庫遷移
git倉庫的遷移,在一些git管理平台像是gitlab和github是有的,推薦使用平台提供的方法,如果沒有的話我們則可以使用git語句操作:
git clone --bare git@host/old.git # clone原倉庫的裸倉庫
cd old.git
git push --mirror git@host/new.git # 使用mirror參數推送至新倉庫
國際化/本地化注意事項
國際化和本地化之間的差別雖然微妙,但卻很重要。國際化意味着産品有适用于任何地方的“潛力”;本地化則是為了更适合于“特定”地方的使用,而另外增添的特色。用一項産品來說,國際化隻需做一次,但本地化則要針對不同的區域各做一次。這兩者之間是互補的,并且兩者合起來才能讓一個系統适用于各地。
除了大頭的語言本地化,還有布局、字元、日期、數字等本地化工作,更多了解可以參考iOS國際化及本地化(一)不同語言的差異處理及測試[1]。
這裡講兩點,日期格式和數字表示:
日期格式
日期格式在國内的通常記法是yyyy-mm-dd,年月日的格式,但是不同地區它們的習慣會有所不同,以下按地區劃分:
參考:https://zh.wikipedia.org/wiki/%E5%90%84%E5%9C%B0%E6%97%A5%E6%9C%9F%E5%92%8C%E6%97%B6%E9%97%B4%E8%A1%A8%E7%A4%BA%E6%B3%95
數字表示
千分符在不同地區會有三種寫法,逗号
,
、句号
.
、空格 ,小數點的寫法有句号
.
、逗号
,
兩種。通常為了便于區分,同一符号不會既做千分符,又做小數點。為了避免歧義,國際标準建議使用空格作為千分符,而不是空格或者小數點。
比如對「一百二十三萬四千五百六十七點八九」進行表示:
中國、美國、澳洲:1,234,567.89
德國、荷蘭:1 234 567,89或1.234.567,89
法國、意大利:1 234 567,89
各個地區對小數點的使用可以看這張圖的總結:
參考資料:https://zh.wikipedia.org/wiki/%E5%B0%8F%E6%95%B8%E9%BB%9E
那些bug
Cateogry和Extension使用相同名稱擴充的問題
bug出現的現象是什麼樣的?
對SDK的一個類擴充時,使用了相同的名稱擴充
Extension擴充
@interface LSDeviceInfo (LSWatch)
@property(nonatomic, assign) LSWatchType type;
@end
Cateogry擴充,并實作了type的getter方法
@interface LSDeviceInfo (LSWatch)
- (LSWatchType)type;
@end
錯誤不是每次都會出現,Xcode12.3一開始是偶現,出現後就一直是報錯。
Unable to execute command: Segmentation fault: 11
Clang frontend command failed due to signal (use -v to see invocation)
Diagnostic msg: PLEASE submit a bug report to http://developer.apple.com/bugreporter/ and include the crash backtrace, preprocessed source, and associated run script.
Diagnostic msg:
PLEASE ATTACH THE FOLLOWING FILES TO THE BUG REPORT:
Preprocessed source(s) and associated run script(s) are located at:
Diagnostic msg: /var/folders/tp/4kw93qbn7tb20cbpn14fmwk00000gn/T/RLWifiConfigFailedViewController-243a91.m
是如何解決的?
将Cateogry擴充和Extension擴充的擴充名設定為不同的,這個錯誤就解決了。
bug引發的反思
extension在編譯期決議,它就是類的一部分,在編譯期和頭檔案裡的@interface以及實作檔案裡的。然後category是在運作期加入hashTable表,extension擴充的名稱和category一樣,這個時候可能在hashTable表上已經有了對應名稱的資料,category在加入時就會出錯。Xcode這時候也可能錯以為維護hashTable表出錯,讓送出對應的bug到http://developer.apple.com/bugreporter/。
程式設計概念
什麼是Clang
Clang 是一個C、C++、Objective-C和Objective-C++程式設計語言的編譯器前端。它的目标是提供一個GNU編譯器套裝(GCC)的替代品,支援了GNU編譯器大多數的編譯設定以及非官方語言的擴充。作者是克裡斯·拉特納(Chris Lattner)。
clang項目包括clang前端和clang靜态分析器。編譯器前端的含義是clang不能直接将源碼編譯成機器碼,clange能輸出源碼的抽象文法樹,并将代碼編譯成LLVM bitcode。
Clang本身性能優異,其生成的AST所耗用掉的記憶體僅僅是GCC的20%左右,Clang編譯Objective-C代碼時速度為GCC的3倍,還能針對使用者發生的編譯錯誤準确地給出建議。
什麼是LLVM
LLVM(Low Level Virtual Machine)是一個自由軟體項目,它是一種編譯器基礎設施,以C++寫成,包含一系列子產品化的編譯器元件和工具鍊,用來開發編譯器前端和後端。它是為了任意一種程式設計語言而寫成的程式,利用虛拟技術創造出編譯時期、連結時期、運作時期以及“閑置時期”的最優化。
LLVM有兩層含義,廣義的LLVM是指一個完整的編譯器架構,包括前端、後端、優化器等。
狹義的LLVM僅指編譯器後端功能的一些列子產品和庫,由Clange編譯出的中間件經過LLVM後端處理變成對應機器碼。
什麼是ld
連結器(Linker)是一個程式,它可以将一個或多個由編譯器或彙編器生成的目标檔案外加庫連結為一個可執行檔案。
ld是GNU的連結器,llvm4中有了自己的連結器lld,但是lld在macOS上運作還有問題 (http://lists.llvm.org/pipermail/cfe-dev/2019-March/061666.html),是以目前Xcode使用的連結器仍是ld。
Build Setting裡的Other Linker Flags就是制定ld指令的參數。
在Xcode中,它有三個常用的參數:
-Objc
:連結器就會把靜态庫中所有的 Objective-C Class 和 Category 都加載到最後的可執行檔案中
-all_load
:會讓連結器把所有找到的目标檔案都加載到可執行檔案中,但有可能會遇到
duplicate symbol
錯誤
-fore_load
:需要指定加載庫檔案的路徑,然後将目标檔案全部加載到可執行檔案中。
什麼是dyld
dyld(the dynamic link editor)是蘋果的動态連結器,負責程式的連結及加載工作,是蘋果作業系統的重要組成部分。
dyld跟ld不同點在于它主要是用于加載系統動态庫的,在MachO内記錄了所依賴的動态庫,像是Foundation、UIKit等,應用啟動時由dyld進行加載。首次加載會将動态庫放至共享緩存,之後需要加載的應用就可以直接通路共享緩存加載這些動态庫了,之後連結至主程式。
dyld屬于開源項目,位址:https://opensource.apple.com/tarballs/dyld/
什麼是bitcode
bitcode是編譯後的程式的中間表現,在Xcode中bitcode對應的是一個配置,意為是否開啟bitcode。
包含bitcode并上傳到App Store Connect的Apps會在App Store Connect上編譯和連結。包含bitcode可以在不送出新版本App的情況下,允許Apple在将來的時候再次優化你的App 二進制檔案。對于iOS Apps,Enable bitcode 預設為YES,是可選的(可以改為NO)。對于WatchOS和tvOS,bitcode是強制的。如果你的App支援bitcode,App Bundle(項目中所有的target)中的所有的Apps和frameworks都需要包含bitcode。
蘋果推薦iOS項目開啟bitcode,且強制watchOS必須開啟bitcode。
因為包含bitcode的項目會在App Store Connect重新編譯,是以其符号表檔案依賴編譯後的結果,這時就需要從App store connect下載下傳對應dSYM檔案。
什麼是linkmap
我們編寫的源碼需要經過編譯、連結,最終生成一個可執行檔案。在編譯階段,每個類會生成對應的
.o
檔案(目标檔案)。在連結階段,會把.o檔案和動态庫連結在一起。
linkmap(Link Map File)指的就是記錄連結相關資訊的純文字檔案,包含可執行檔案的路徑、CPU架構、目标檔案、符号等資訊。其可用于分析iOS編譯後各個子產品的大小,網上也有一些現成的工具幫助我們直接分析該檔案。
在Build Setting裡搜map,可以看到
write link map file
選項,裡面設定了linkmap檔案的導出路徑。
優秀部落格
GitHub 2020 報告:全球開發者工作與生活的平衡情況[2]
2020 騰訊Techo Park - Flutter與大前端的革命[3]
WWDC20 iOS14 Runtime優化[4] -- 來自公衆号:知識小集
使用 Swift 編寫 CLI 工具的入門教程[5] -- 來自公衆号:一瓜技術
阿裡 10 年:一個普通技術人的成長之路[6]
2020年剛過完,有挺多寫的非常好的年終總結可以看看:
寫在2020最後一天 -- 來自公衆号:iOS成長之路
如何持續的自我提升 -- 來自公衆号:酷酷的哀殿
2020 的 cxuan 在掘金 | 掘金年度征文[7]
中年裸辭,我的2020 | 掘金年度征文[8]
2020:非适應性完美主義、存在主義哲學、架構、基金翻倍、有效休息|掘金年度征文[9]
學習資料
提問的智慧[10]
開發過程中遇到問題是非常常見的,解決問題的過程免不了要向别人或者社群論壇提問,而提問方式的好壞通常決定了你能否獲得想要的答案。有這麼一個github倉庫:How-To-Ask-Questions-The-Smart-Way star數高達13.7k,專門講述如何更有效的提問,很多論壇也将這個作為提問準則,用于提醒大家有效提問的重要性。
一個好的提問,即表達了自己對問題答案的渴望,也表達了對解答者的尊重。
LeetCode Cookbook[11]
halfrost 總結的leetcode算法題解,使用go語言完成,書中各個題目代碼都已經beats 100% 了。
開發利器
推薦好用的開發工具。
A Companion for SwiftUI
推薦來源:AlleniCode
下載下傳位址:https://apps.apple.com/cn/app/a-companion-for-swiftui/id1485436674?mt=12
軟體狀态:付費¥328.00
作者的 SwiftUI 實驗室,A Companion for SwiftUI 是一款可以記錄 iOS 和 macOS 平台的 SwiftUI 視圖,形狀,協定,場景和屬性包裝的應用程式。該應用程式還包含每種方法的示例,其中有許多都是互動式的,并且嵌入在應用程式中運作。通過使用關聯的控件,你可以看到它們對視圖的直接影響,以及如何修改你的代碼以産生這樣的效果。
Go2Shell - 在終端中打開目前Finder目錄
推薦來源:RayLeeBoy
下載下傳位址:https://zipzapmac.com/go2shell
軟體狀态:免費
使用介紹:
- 輕按兩下下載下傳的檔案, 将Go2Shell拖入Applications目錄中
- 在Applications中, 輕按兩下打開Go2Shell, 出現下面的視窗
iOS摸魚周報 第二期 - 點選Install Go2Shell to Finder完成安裝
- 打開Finder視窗, 在工具欄中出現Go2Shell圖示
- 點選Go2Shell圖示, 就會在終端中打開目前Finder目錄
使用 Alfred 制作打開終端的快捷鍵
這是我目前在用的一種形式,前提是需要安裝Alfred:選中某一檔案,按下
Command+ T
,就可以打開終端并定位到該檔案夾路徑。它和Go2Shell實作效果類似,但它可以不依賴Finder,對于桌面檔案的操作更友好一些。
實作方式如下:
1、在Workflows裡建立HotKeys,編輯快捷鍵
Command + T
2、右鍵該HotKeys > Insert After > Actions > Run Script 建立腳本
3、腳本編輯視窗選擇腳本語言:/usr/bin/osascript(AS),意為Apple Script
4、在腳本框輸入如下腳本,儲存即可:
tell application "Finder"
-- get selection path
set pathFile to selection as text
set pathFile to get POSIX path of pathFile
-- fix space problem in the directory
set pathFile to quoted form of pathFile
tell application "iTerm"
create window with default profile
tell current session of current window
write text pathFile
end tell
end tell
end tell
該腳本是針對
iTerm
終端設定的。
參考資料
[1]
iOS國際化及本地化(一)不同語言的差異處理及測試: https://zhangferry.com/2019/08/19/localization_guide/
[2]
GitHub 2020 報告:全球開發者工作與生活的平衡情況
[3]
2020 騰訊Techo Park - Flutter與大前端的革命
[4]
WWDC20 iOS14 Runtime優化: https://mp.weixin.qq.com/s/opD__14wpHL06VKPtXeM4g
[5]
使用 Swift 編寫 CLI 工具的入門教程: https://mp.weixin.qq.com/s/V4IdsYUouKGr68ULyb88Qw
[6]
阿裡 10 年:一個普通技術人的成長之路
[7]
2020 的 cxuan 在掘金 | 掘金年度征文
[8]
中年裸辭,我的2020 | 掘金年度征文
[9]
2020:非适應性完美主義、存在主義哲學、架構、基金翻倍、有效休息|掘金年度征文
[10]
提問的智慧: https://github.com/ryanhanwu/How-To-Ask-Questions-The-Smart-Way