Nelson 寫些 iOS 開發的東東

為何 Git-Flow 可能不適合你

| Comments

什麼是 Git-Flow

Git-FlowVincent Driessen 在 2010 年提出的一套 Git 分支模型,簡單的說,它有 masterdevelop 這兩個主要的分支,以及 feature / release / hotfix 這三個支援型分支,至於各個分支的用途看圖片應該就懂了,或是看原文有更詳細的說明。

由於當時大家對如何使用 Git 還處於摸索的階段,所以當這套規範被提出並且大家發現真的滿好用的之後,它很快就被廣泛的接受。

如何解決 NSTimer 造成的 retain cycle

| Comments

故事是這麼開始的

最近在替公司 app 做健康檢查,找到一些 memory leaks 的問題,其中一個就是由 NSTimer 所引起的 retain cycle。

NSTimer 是個很容易造成 retain cycle 的物件,無論是新手或是老手都很可能一個不留意就踩到這個坑。舉個很常見的例子,這樣寫就產生 retain cycle 了:

@interface MyViewController()
@property (nonatomic, strong) NSTimer *timer;
@end
  
@implementation MyViewController
- (void)viewDidLoad {
  [super viewDidLoad];
  self.timer = [NSTimer scheduledTimerWithTimeInterval:0.5 target:self selector:@selector(timerFired:) userInfo:nil repeats:YES];
}
- (void)dealloc {
  [_timer invalidate];
  _timer = nil;
}
- (void)timerFired:(NSTimer *timer) {
  // Do something...
}
@end

一個 AFNetworking 的 retain cycle 問題

| Comments

AFNetworking 封裝了網路連線的許多工作,讓 iOS/Mac 開發者可以用簡潔的寫法去處理連線,但你知道要如何正確使用,才不會出現 retain cycle 嗎?

舉個例子

舉個最簡單的例子,我們可能會在自訂的 UIViewController 裡頭建立一個 AFHTTPSessionManager,透過它來進行網路連線,大部分的寫法大概如下:

@interface MyViewController ()
@property (nonatomic, strong) AFHTTPSessionManager *manager;
@end

@implementation MyViewController
- (void)viewDidLoad {
    [super viewDidLoad];
    self.manager = [AFHTTPSessionManager manager];
    // Do something with self.manager...
}
@end

簡單直覺,對吧?但是你會發現在 view controller 被摧毀之後,這個 AFHTTPSessionManager 還存留在記憶體裡面,不信的話可以用 Xcode 的 Memory Graph 檢查看看。

你不信邪,所以你可能會試著在 dealloc 把它設為 nil,這樣總該沒問題了吧?

- (void)dealloc {
    _manager = nil;
}

可惜的是,這樣做沒有用,它依然存在記憶體裡。怎!麽!可!能!原因在一開始就提到了,因為它有 retain cycle。正確釋放的做法如下,你需要先呼叫 invalidateSessionCancelingTasks: 這個函式:

- (void)dealloc {
    [_manager invalidateSessionCancelingTasks:YES];
    _manager = nil;
}

為什麼會這樣

因為 AFHTTPSessionManager 擁有一個 NSURLSession *session property,而且把這個 session 的 delegate 設為 self,而 NSURLSessiondelegate 設為 retain。所以它們互相擁有彼此,造成了 retain cycle。

當我們呼叫 invalidateSessionCancelingTasks: 函式,它會去呼叫 NSURLSessioninvalidateAndCancelfinishTasksAndInvalidate。根據蘋果文件,呼叫這兩個函式之後,NSURLSession 才會斷開它與 delegate 的關聯。至此,才打破 retain cycle。

解法

有兩個解法,第一個就是如上所述,記得最後要呼叫 invalidateSessionCancelingTasks: 來結束任務。第二個就是把 AFHTTPSessionManager 寫成 singleton,這樣有 retain cycle 也無所謂了。

為何 Startup 不該用 Swift

| Comments

最近跟朋友聊天,聊到說我不建議 startup 使用 Swift 開發 app,趁著有空紀錄一下為何我會這麼說。

還是得先聲明一下,Swift 是一個很酷的語言,我沒有不喜歡它,只是站在公司的角度,我認為 startup 不應該使用 Swift 開發它們的主力產品,而是應該用 Objective-C。

主要是因為以下幾點理由:

Swift 還不穩定

Swift 是一個很新的語言,大家都還在摸索怎樣才是 best practice,但它同時也是一個快速成長與變化的語言,可能去年的 best practice 今年就不適用了。此外它也是一個尚未穩定的語言,剛推出的 Swift 3 還不能向下相容呢。

身為 iOS 開發者,每年都要為了升級 iOS 跟 Xcode 花一番心力。如果選擇用 Swift,那就得多花時間來處理 Swift 版本升級,甚至還要處理第三方套件因為升級而無法使用的問題。這是可以避免的,你只要一開始使用 Objective-C 開發即可。

對 startup 來說時間特別寶貴,我認為把時間花在升級 Swift 並不值得,更別說還得承擔升級之後 app 壞掉的風險。

將有經驗的工程師拒於門外

如果工程師只會 Swift 不會 Objecitve-C,代表他的 iOS 開發資歷並不久,如果使用 Objecitve-C 開發,至少可以確保找來的工程師經驗會多一點,對 startup 來說找到有經驗的人是很重要的事(雖然通常很難...)

也有一些有經驗的工程師因為種種原因還沒學習 Swift,如果哪天公司跟這樣的工程師搭上線,卻因為對方不會 Swift 所以無法提供更多有用的建議給你,這樣不是很可惜嗎?

Objective-C 沒有不好

如果你的公司裡頭有工程師提議要用 Swift 開發,理由是因為「Swift 很潮、想玩玩看」,那你們公司可能找了一位只想追求新技術的人。

使用新技術沒有不好,但要有充分的理由,你開公司找人來上班不是為了實驗新技術的。Objective-C 很成熟,無論是 best practice 或是資源都很完整,沒有什麼理由不用它。


以上都是站在 startup 的角度來說明為何不要用 Swift 開發主力產品,如果你們是一個大公司,或者工程團隊有強者坐鎮,或者你只是想寫個 side project 玩玩看,當然就無所謂。

讓 Xcode 8 再度支援 plugins

| Comments

眾所皆知的,Xcode 8 把之前的 plugins 都擋掉了,然後推出了 Source Editor Extension,但 Source Editor Extension 的能力還很有限,基本上只能對「文字」操作。

所以就有人提出了一個解法,把 Xcode 8 app unsign,這樣就能讓 plugins 再度作用了。具體作法如下:

  1. 下載 MakeXcodePluginsWork
  2. chmod 755 makeXcodePluginsWork 然後執行它
  3. 啟動 Xcode,原有的 plugins 都回來了

這樣會把 Xcode.app 的 signing 關掉,會變得比較不安全(其實就算跟之前一樣而已),所以請自己小心,後果自負。附帶一提,Xcode 8 開始內建一些功能,有些 plugins 可以退休了,例如:

  • 可以高亮度當前列,從【Preferences -> Fonts & Colors】設定「Current Line」顏色
  • 可以產生註解文件,熱鍵是【Command + Option + /】