[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 3GS/4 で使える Bluetooth キーボード ELECOM TK-FBP017BK

フォローしている人のつぶやきで発見した記事で知ったキーボード。iPhone4ユーザー必携Blueto

記事を読む

no image

Xcode + Assembla で Subversion でソース管理

ソースコードはUSB HDDにバックアップしているが、震災が来たらHDDを持って逃げられるとは思え

記事を読む

AWS IoTを利用してクラウド連携機能を追加してみた

GWに自宅待機でまとまった時間が確保できたので、AWS IoT を利用してMQTTを使った

記事を読む

no image

ゲームデザイン脳 のiPhoneアプリ版

ゲームデザイン脳のiPhoneアプリ版が出たらしい。 無料で、しかも書き下ろしもある模様。 本の購入

記事を読む

GoodNotes5使いこなし

iPad Pro 12.9インチを購入した 理由の一つである、Apple Pencil

記事を読む

no image

[iPhone 開発本] iPhone Advanced Projects がおもしろい

Apressのページはこちら。公開されているサンプルコードは43MBもある。

記事を読む

英辞郎第7版からアルクのSVLを EverLearn に取り込む方法

英辞郎 第七版(辞書データVer.136/2013年1月8日版)アルク企画開発部 アルク 2013

記事を読む

no image

はじめてのiPhoneプログラミング

さらにiPhoneプログラミング本が出るらしい。出版ラッシュですな。 これは568ページもあるらしい

記事を読む

[iOS][SDK]UIImageをファイルとして保存したい

オンデバイスで学習を行ったときに、将来使えるように UIImage も画像ファイルとして保存してお

記事を読む

no image

Learn iPhone and iPad Cocos2D Game Development

洋書だけれども、ApressからCocos2d を使ってゲーム開発する本として Learn iPho

記事を読む

Message

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

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

Wi-Fi6Eルータ TP-Link AXE5400購入

Wi-Fi6E を試してみたくなり、TP-Link AXE5

児童手当 認定請求書申請 2024 「請求者が養育をする18歳に達する日以降の最初の3月31日までの子の数」とは?

2024年に受給していない人には手紙が届くらしい。 電子申請も

Vision Proアプリ開発本 8/24、8/26に発売

Vision Proアプリ開発入門 P400が 8/24 に発売、V

Developer Strap が日本でも購入可能に

USアカウントでしか購入できなかった Vision Pro 用 De

Vision Pro カバーケースを買ってみた

[itemlink post_id="11629"]

→もっと見る

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