ObjecTips

Swift & Objective-C で iOS とか macOS とか

viewWillDisappear: では super をいつ呼ぶべきか

- (void)viewWillDisappear:(BOOL)animated
{
    [super viewWillDisappear:animated];
    // some implements
}

- (void)viewWillDisappear:(BOOL)animated
{
    // some implements
    [super viewWillDisappear:animated];
}

どちらが良いの?という議題

Appleのドキュメント

Subclasses can override this method and use it to commit editing changes, resign the first responder status of the view, or perform other relevant tasks. For example, you might use this method to revert changes to the orientation or style of the status bar that were made in the viewDidDisappear: method when the view was first presented. If you override this method, you must call super at some point in your implementation.

最後の1文にメソッドをオーバーライドする場合は実装のどこか (at some point) で super を呼ばなければならないとの記述がある。
呼ぶべきタイミングについては自由という様にも解釈できる。

クラスヘッダ

- (void)viewWillDisappear:(BOOL)animated; // Called when the view is dismissed, covered or otherwise hidden. Default does nothing

デフォルトでは何もしないという記述がある。
何もしないのであれば [super viewWillDisappear:animated]; はどこで呼んでも影響が無い、むしろ呼んでも呼ばなくても同じとも言える。

Appleのサンプルコード

iOS Dev Center で viewWillDisappear: で検索して Sample Code タブを選択

https://developer.apple.com/search/?q=viewWillDisappear&type=Sample%20Code

検索にかかったサンプルコードを確認

サンプルコード 処理の最初に super 処理の最後に super
SimpleUndo YES
Lister (for Apple Watch, iOS, and OS X) YES
MetalShaderShowcase YES
AVPlayerDemo YES YES
BTLE Central Peripheral Transfer YES
MetalTexturedQuad YES
MetalVertexStreaming YES
StreetScroller - -
MetalImageProcessing YES
AVMetadataRecordPlay: Timed Metadata Capture Recording and Playback YES
Alternate Views YES
pARk - -
AppPrefs: Storing and Retrieving User Preferences YES
Tabster - -
MVCNetworking YES
AVCustomEdit YES
AirLocate: Using CoreLocation to monitor, range, and configure your device as an iBeacon YES
GeocoderDemo YES
MetalBasic3D YES
CustomFonts - -
MetalInstancedHelix YES
SimpleTunnel: Customized Networking Using the NetworkExtension Framework YES
PhotosByLocation YES
AVTimedAnnotationWriter: Using Custom Annotation Metadata for Movie Writing and Playback YES
UICatalog: Creating and Customizing UIKit Controls YES
HomeKit Catalog: Creating Homes, Pairing and Controlling Accessories, and Setting Up Triggers YES
MetalDeferredLighting YES
MetalUniformStreaming YES
MetalVideoCapture YES
MultipeerGroupChat YES
MoviePlayer YES
StacheCam - -
AVCompositionDebugVieweriOS YES
Spaceship YES
CoreDataBooks YES
SceneKit Vehicle Demo - -
SloPoke YES
State Restoration with Collection View YES
UIKit Printing with UIPrintInteractionController and UIViewPrintFormatter - -
TableView Fundamentals for iOS - -
SquareCam - -
MediaNotes - -
SharedCoreData - -
Running With a Snap - -
Real-time Video Processing Using AVPlayerItemVideoOutput - -
AVCaptureAudioDataOutput To AudioUnit iOS - -
AVCompositionDebugViewer - -
AirDrop Examples - -
AdvancedURLConnections - -
EADemo - -
Audio Mixer (MixerHost) YES

大抵が最初に super を呼ぶパターンで、一部は super を最後に呼ぶパターンになっている。
AVPlayerDemo については ViewController によってそれぞれ異なる形で super が呼ばれているため両方が YES になっている。
super を呼んでいなかったり、super を呼んでいるだけで前後に実装の無いものはハイフンで記載している。

それぞれのパターンで viewWillDisappear: でどのような処理を行っているかをまとめた。

最初に呼んでいるパターン
  • resignFirstResponder
  • delegatenil に設定する
  • completionHander を nil に設定する
  • NSNotificationCenter の通知解除
  • KVO の通知解除
  • UIToolBar の状態変更
  • statusBar の状態変更
  • ゲームループの停止
  • UIControl の enabled の状態変更
  • フラグのリセット
  • AVPlayer の再生停止 (AVCustomEdit, AVTimedAnnotationWriter, AVCompositionDebugVieweriOS)
  • CLLocationManager の位置情報更新停止
  • UIActivityIndicator の停止
  • networkActivityIndicatorVisible を停止
  • CADisplayLink の停止
最後に呼んでいるパターン
  • AVPlayer の再生停止 (AVPlayerDemo, SloPoke)
  • CBCentralManager のスキャン停止
  • CBPeripheralManager のアドバタイズ停止
  • NSNotificationCenter の通知解除 (PhotosByLocation)
  • delegatenil に設定する (PhotosByLocation)
  • UINavigationBar の状態変更 (SloPoke)
  • UIApplication リモートコントロールイベントの受け取り停止

PhotosByLocation を除いては NSNotificationCenter と KVO の通知解除、delegate への nil の設定は super を呼んだ後に行っている。
AVPlayer の停止は半々ぐらいのケースに分かれる。

いつ呼ぶべきか

呼ぶ「べき」タイミングはないと思う。各々の実装で良いかと。
viewWillAppear: で何らかの tear down 系の処理を行っていてその ViewController をサブクラス化して使うケースで、サブクラスによる追加の tear down 系の処理と super との処理の順番が重要な場合には super を呼ぶタイミングは意識する必要が出てくる。
通常の UIViewController のサブクラスにおいて通知解除、画面表示の更新停止、継続的なデータフェッチの更新停止などのみを行う場合にはタイミングは気にしなくても良い。
チーム作業での混乱を防ぐためにコーディングガイドラインで、基本的にはいつ super を呼ぶようにするか、どのようなケースで基本から外れるのか認識を合わせておくのも良いと思う。