情境

有兩個ViewController,分別為A 跟B:

A – 一個NavigationController 的rootViewController,擁有TabBar,但非使用TabBarController

B – 一個一般的UIViewController

當我們從A push 到B 時,TabBar 是不會消失的,一般來說,若使用UITabBarController,可以透過修改UIViewController 的property hidesBottomBarWhenPushed 來隱藏TabBar。

但公司的專案當中,當時因為一些歷史包袱並沒有使用UITabBarController,因此必須實作UINavigationControllerDelegate當中的navigationController:willShowViewController:animated:方法,藉此觀察目前的ViewControllers stack 的狀況來決定是否要隱藏TabBar。

舉例來說,當從A push 到B 時,navigationController:willShowViewController:animated:的 willShowViewController 則會是B ,從B pop 回A 時則相反,若發現willShowViewController 是A 時(或特定的viewController),則隱藏TabBar,因此得正面表列很多狀況,程式碼也變得髒髒的。

問題點

不過在一般的操作下,儘管程式碼不乾淨,這樣的作法似乎沒什麼問題,但是navigationController:willShowViewController:animated:這個delegate method 只要準備啟動navigation 時就會被invoke。
因此,Bug 發生在如果一個使用者透過UINavigationController 內建的swipe gesture 來從B pop 回A,當滑動事件開始時(儘管只滑動一點點),delegate method 就會被invoke,此時若直接放開滑動中的B,若滑動的距離不夠,則會回到B 並且取消pop 的動作,但這下就糟了,此時的willShowViewController 是A ,原本的實作也決定要顯示出TabBar,這時就發生了明明本來該回到A,但他被取消了卻顯示了不該顯示的TabBar 的窘境。

因此找了一下方法,來監聽系統其實取消了滑動事件,而我們也放棄原本做的決定(顯示TabBar):

- (void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated
{
        id<UIViewControllerTransitionCoordinator> tc = navigationController.topViewController.transitionCoordinator;
        [tc notifyWhenInteractionEndsUsingBlock:^(id<UIViewControllerTransitionCoordinatorContext> context) {
            NSLog(@"Is cancelled: %i", [context isCancelled]);
    }];
}

 

如此一來,我就知道滑動轉場事件是取消的,而我自行新增了一個local var 來儲存轉場前的狀態,若被取消則將狀態設回,就解決掉現有程式碼所遇到的問題拉。

 

結論

好吧,問題是解了,但是總覺得SDK 本身提供了你這些功能,實作上卻用偏門左道去實作,最後再用其他方法來解決自己遇到的問題,維護成本很大,不是嗎?可惜的是,這樣的狀況卻在專案內層出不窮,哈哈哈,理想與現實還是有點遠的。