[iPhone開発のネタ帳] loadView, viewDidLoad と viewDidUnload 2011/08/12

公開日: : iPad, iPhone ,

拙作のiPadアプリ タッチ!にほんちずタッチ!ヨーロッパ地図でUIWebViewControllerでWikipediaを表示したり、ランキング表示をしたりするようになってから、結構頻繁に didReceiveMemoryWarning や viewDidUnload が呼ばれるようになった。
これにより問題が起き、芋づる式にいろいろ調べることになってしまったのでそのメモを残してみる。

調べたこと

  • loadViewとviewDidLoad の使い分け
  • viewDidUnload で何が解放されるか
  • viewDidUnload が呼ばれてしまったらどんな対応をすればよいか
  • nibファイルを使わない(Interface Builderを使わない)開発(これはおまけ)

didReceiveMemoryWarning は、アプリケーションで使用しているメモリが多くなり、メモリ枯渇状態になったときに裏にいるviewをもつ UIViewController に対して呼ばれるという理解をしている。
didReceiveMemoryWarning のデフォルトの処理は UIViewController の view が解放できるかをチェックし、解放できると判断した場合、view を解放し、viewDidUnload を呼ぶ。
アプリとしては didReceiveMemoryWarning を受け取ったら解放できるメモリがあれば解放して、以降の処理が継続できるようにすべき。(でないとそのうちメモリが枯渇してアプリが強制終了される)
自分の記憶だと、didReceiveMemoryWarning の中である程度メモリを解放できていれば、view は解放されず、viewDidUnload も呼ばれない、だと思っていたがドキュメントによるとそういうことは書かれていないようだ。
ただ、実際に動かしてみるとdidReceiveMemoryWarning が呼ばれても必ず viewDidUnload まで到達するわけではないし、warning にはレベルがある気がするがそこまではまだ調べていない。

ちなみに手元の本にあたってみたところ、いくつかの本にもviewDidUnload の話があった。
はじめてのiPhone3プログラミング P.106 「善良なメモリ市民になる」によると、メモリ枯渇状態が発生し、nib ファイルがアンロードされると、viewDidUnload が呼ばれる。
nib は解放されるが、コード上で、例えば
@property (nonatomic, retain) IBOutlet UILabel *titleLabel;
などしている場合 retain カウンタが増えてしまっているので、viewDidUnload で手動で
self.titleLabel = nil;
をする必要がある。
このコードにより、実際は [iPhone SDK] Objective-C 2.0 のプロパティ が行われるので、コード上はただの nil の代入に見えるが、実際は release が行われて、retain カウントが減って0になり、オブジェクトは解放される。

self.titleLabel = nil;

titleLabel = nil;

は大きく異なる。(最初によくはまる問題)
ちなみに、このドット記法は Objective-C 2.0 で導入されたらしいけれども、上記のように分かりづらい問題が発生することがあり無用に問題を複雑にすることがあるので、アーロン・ヒレガス氏はMac OS X Cocoaプログラミング 第三版 P.124 で「私自身はこういった記法の追加によって言語が無駄にややこしくなったと考えています。このため、本書ではこの記法を採用していません」と書いている。

ということで、これを調べている間に見つけた
ヒビノアワ: iOS SDKのviewDidUnloadでoutletを解放するべきか否か
に対する回答としては、viewDidUnload で解放する必要がある(はず)。

iPhoneプログラミングUIKit詳解リファレンス P.116 にも viewDidUnload の記載があり、viewDidUnload でメモリを解放しようと書かれているが、もし不要なメモリがあればまずは didReceiveMemoryWarning で行うのが正しいと思われる。

このOSによる強制的な nib (というかview) の解放が行われた場合、そのままだと nib でロードしたオブジェクトがない状態になってしまうので、自動的に viewDidLoad が呼ばれることになる。
(viewDidLoad は通常UIViewControllerの生存期間中に一度しか呼ばれないが、viewDidUnload が呼ばれたときのみ2回以上呼ばれることになる)

自分は viewDidLoad にアプリのほとんどの初期化処理を書いていたが、実際にはErica女史が好んで使う UIViewControllerの loadView が先に呼ばれる。
loadView で実際何が行われているかなどはここでくわしく考察されている。
iPhoneアプリ開発、その(164) きっかけはself.view|テン*シー*シー

Interface Builder(IB) を使っている場合、UIViewControllerのプロパティnibNameにnibファイル名が書かれているはずなので、それをもとに loadView でUIViewControllerのviewプロパティにUIView が設定される。
UIViewController Class Reference
によると、view プロパティが設定されると、次に viewDidLoad が呼ばれる。
コードで init でオブジェクトを生成する場合には loadView 内に記述し、nib ファイルでロードするオブジェクトに関しては viewDidLoad を使うような使い分けをするような記憶があるが、しかしnibファイルでロードしたオブジェクトに対して、その後にコードで init する部品もいろいろある場合はどうすればよいのか。
上記の テン*シー*シー にも書かれているが、IBを使っている場合は、コードでUI部品を init している場合でも、このviewDidLoad に書いてしまっても良いと思っている。

ここで、ようやく本題のviewDidUnload の話になる。
viewDidUnload が呼ばれると、通常一度しか呼ばれない viewDidLoad が再度呼ばれてしまうので、上記のように viewDidLoad でいろいろ初期化している場合には2回以上初期化されてしまうことになってしまう。
このため、それに備えて viewDidUnload には viewDidLoad で確保しているオブジェクトなどを解放するコードを書いておく必要がある。
(もしくは、フラグを立てたりして二重に確保しないようにする)
自分は viewDidUnload に解放処理を書いていなかったので、2回目の viewDidLoad で二重に初期化処理が行われていろいろ問題が起きていたのだった。
ということで、一応解決。

ちなみに viewDidLoad と viewDidUnload と dealloc の関係はよく勘違いされていることがあるので、その場合はこちらをどうぞ。
Cocoaの日々: UIViewController でのメモリ管理見本
viewDidLoad と viewDidUnload は対になっていつでも呼ばれそうな気がするが、実際にはメモリ枯渇状態になったときしか viewDidUnload は呼ばれないので、通常の終了処理は dealloc に書いておく必要がある。(viewDidUnload だけに書いておいても、通常の流れでは呼ばれない)

このあたりのことは、iOS開発におけるパターンによるオートマティズム P.100 からくわしく書かれていた。

ちなみに IB を全く使わずにコーディングしたい場合、こちらを参照するのが良さそう。

IBや、ドット記法などは分かって使っていれば便利だけれども、これらを使わないでプログラミングすれば、もう少し複雑度は下がる気がするし、iPhone SDK勉強会で説明するネタも減りそうだ。
しかしAppleがサンプルプログラムなどで積極的に使っているのでなかなかそうはいかないと思うけれども。

いろいろ書いたので何か間違いがあればコメントください。

はじめてのiPhone3プログラミング
はじめてのiPhone3プログラミング Dave Mark Jeff LaMarche 鮎川 不二雄

ソフトバンククリエイティブ 2009-12-17
売り上げランキング : 36737

Amazonで詳しく見る by G-Tools

Mac OS X Cocoaプログラミング 第三版
Mac OS X Cocoaプログラミング 第三版 Aaron Hillegass アーロン ヒレガス 村上 雅章

ピアソン桐原 2009-11-01
売り上げランキング : 26181

Amazonで詳しく見る by G-Tools

iPhoneプログラミングUIKit詳解リファレンス
iPhoneプログラミングUIKit詳解リファレンス 所 友太 京セラコミュニケーションシステム株式会社

リックテレコム 2010-01-12
売り上げランキング : 6167

Amazonで詳しく見る by G-Tools

iOS開発におけるパターンによるオートマティズム
iOS開発におけるパターンによるオートマティズム 木下 誠

ビー・エヌ・エヌ新社 2011-02-09
売り上げランキング : 15835

Amazonで詳しく見る by G-Tools

関連記事

heroku Cedar-10からCedar-14に引越し

2015/11/04 に Cedar-10 stack が終了となる連絡が heroku からきたの

記事を読む

LogLocations 1.4.5 リリース

LogLocations 1.4.5 をリリースしました。 LogLocat

記事を読む

no image

Xcode4 の初Submit作業ではまる 2011/07/11

昨夜、タッチ! にほんちずHDの次のアプリを検証していて、iPadを回転させるとアプリが異常終了して

記事を読む

no image

App Store のスクリーンショットの解像度がいつの間にか変更されている

2ヶ月ぶり位で App Store にアップデートをSubmitしようとしたところ、アップデート

記事を読む

iPhoneとBluetooth連携できる体重計 タニタ RD-900

iPhone と連携できる体重計には以前から興味があって、Withings の WS-30 を狙って

記事を読む

no image

Corona SDK 調査3日目 (Lua 用エディター探しその1)

iPhoneとAndroid両方で動くアプリケーションを開発できるというCorona SDKの調査3

記事を読む

no image

林信行氏 iPhoneの衝撃 セミナー 2009/10/07@代々木 に参加してきた

いまさらながら、2009/10/07(水)に行われた、林信行氏 iPhoneの衝撃 セミナーのレポ

記事を読む

no image

App Store レビュー中

8月13日にApp StoreにSubmitしたiPhoneアプリがまだIn Review状態だ。果

記事を読む

no image

[iPhone SDK] ネットワーク接続中を示すぐるぐるの表示

いつも忘れて検索してしまうので自分のブログにメモ。 iPhoneのインジケーターバー(?)にぐるぐ

記事を読む

Roland 電子ドラム TD-4KP 落札

(2016年2月の記事)ドラム譜学習アプリを作るためには自分も叩けないと困るだろう、ということでMI

記事を読む

Message

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください

REALFORCE MOUSE RFM01U11 ハンズオン中

【Hothotレビュー】今までにないクリック感がゲームプレイも変える

Appleシリコン搭載Mac発表?

いつからか、下記の文言が App Store Connect

[iOS] 取り下げになったアプリを更新

しばらく更新していなかったら App Store から取り下げに

m5stack + MH-Z19B で CO2 濃度を測ってみた

テレワーク期間が長く続いているが、冷房をかけて閉め切った部屋

自動昇降機能付きデスクFLEXISPOT EJ2購入

今後もテレワークが長く続きそうなので、憧れだった自

→もっと見る

  • 2011年8月
    1234567
    891011121314
    15161718192021
    22232425262728
    293031  
PAGE TOP ↑