[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

関連記事

no image

そのまま使えるiPhoneゲームプログラム

書店で見かけて立ち読みしてみた。 ゲームで使いそうな小技が紹介されている。ゲーム向けなので、Open

記事を読む

no image

Corona SDK 調査4日目

今日はスクリプト言語による効率的ゲーム開発を読んで、ちょっとテストプログラムを書いたくらいであまり進

記事を読む

[iOS9] AVSpeechSynthesizer の再生スピードがおかしい

iPhone 6 Plus を iOS9 にアップデートして自作アプリをXcode7 から転送したと

記事を読む

no image

自作iPhoneアプリ いろいろレビュー依頼

アプリ制作日誌 #app_24: iPhoneアプリのレビューを、寄稿・依頼できるサイトまとめ。 と

記事を読む

no image

Cocos2dで作る iPhone&iPadゲームプログラミング

ついに良さそうなcocos2d本が出るらしい。6/24(金)発売予定。488ページ、3980円。 し

記事を読む

[iOS SDK] 消音モードでも音を再生する対応を入れました

昔、 iPhone/iPad はサイレントモードにしても音が鳴る という記事を書いたけれども

記事を読む

EverLearn 1.7.5 を公開しました

英単語学習アプリ EverLearn 1.7.5 を公開しました。変更点エビングハウスの忘却曲線を参

記事を読む

no image

iPad mini 用透明ハードケース eggshell for iPad mini

iPad mini 用にハードケースを購入した。 iPad 用ケー

記事を読む

no image

iPhone Developer Program Activation 完了

iPhone Developer ProgramのActivationの件。 木曜日の夜にメールを出

記事を読む

iOS 13の新機能をざっくり把握する本 購入

https://twitter.com/shu223/status/11517528848553

記事を読む

Message

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

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

ポモドーロテクニック用物理タイマーならTime Timer

会社ではなかなか自由に時間を使えないが、家で読書や作業をする

DELL 32インチディスプレイ U3223QE 購入

Dell U3223QE は解像度 3840x216

WWDC 2023 Vision Pro発表

2023/6/5 (日本時間 2023/06/06 2AM)のWWD

M1 MacBook Air を Venturaにアップデートする

M1 MacBook Air を macOS Montere

iOS16でaurioTouch の inBufferFramesが1になる

https://developer.apple.com/librar

→もっと見る

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