アプリケーションのライフサイクル(2)

2010. 04. 17
いつにも増して英文和訳が怪しいので、鵜呑みにすると危険です。
(特にデリゲート関係は自分で書いていてよく分からない文章になっています)

2)main()関数の呼び出し

main()関数は、アプリケーション起動時に最初に読み込まれるOther Sourcesフォルダ内のmain.mファイルに記述されていて、アプリケーションの初期化を行います。

220

2-1)UIKitフレームワークのインポート

2-2)main()関数の引数

2-3)自動解放プールの作成と解放

2-4)UIApplicationMain()関数の呼び出し

2-5)アプリケーションデリゲートの作成

2-6)UIApplicationDelegateプロトコル

2-7)~AppDelegateの宣言と実装

#import  <UIKit/UIKit.h>

int main(int argc, char *argv[]) {

    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
    int retVal = UIApplicationMain(argc, argv, nil, nil);
    [pool release];
    return retVal;
}


2-1)UIKitフレームワークのインポート

まず1行目で『すべてのiPhoneアプリケーションは、UIKitフレームワークを使用して作成されます』の言葉通り、UIKit.hがインポートされています。


2-2)main()関数の引数

main()関数の引数argcとargvは、コマンドライン引数と呼ばれるもので、コマンドラインからmain()関数を呼び出す際に引数を渡すことができるというC言語の仕様です。
(UIApplicationMainに渡してるので、何を意味しているのかとUIApplicationMain関連を30分も調べていたのは内緒です。どうりで誰も説明しないわけですね)

現実問題として、iPhoneアプリケーションをコマンドラインから呼び出すことは普通しないので無視していいと思います。
(わざわざUIApplicationMainに渡しているということは何か使い道があるとは思いますが)


2-3)自動解放プールの作成と解放

NSAutoreleasePoolは自動解放プールを作るメソッドです。

自動解放については『Objective-C言語のメモ書き(7)』でも説明していますが、軽く紹介します。

プログラムの中で、一時的に利用してすぐ不要になるインスタンスがよくありますが、不要になった後に解放し忘れるとメモリを確保し続け、いわゆるメモリリークの状態になります。

適宜解放すればいい話ではありますが手間がかかりますし、解放し忘れることもあります。

その煩雑さを解消するのが自動解放で、自動解放用に登録されたインスタンスを待機場(プール)に集めておき、後でまとめて解放しようというものです。

インスタンスの生成/初期化時に『autorelease』というフラグを立てることによって登録されるので、一時利用のインスタンスが多数ある場合には一つ一つ解放する手間が省けることになります。

ただしretainでリファレンスカウンタ(参照カウンタ)を増やした場合は、当然解放する回数を合わせなければなりません。

また、テンプレートで作ったプロジェクトではmain()関数に自動解放プールが設定されるものの、このデフォルトの状態ではアプリケーション終了時にまとめて解放することになるので、大量に登録するとメモリが足りなくなるので注意が必要です。
(大量に使用する場所には、別途自動解放プールを設定した方がいいでしょう)

※2010.4.17訂正
24/7 twenty-four seven/autoreleaseされたオブジェクトはいつ解放されるか』によりますと、
 
NSAutoreleasePoolはイベントループが一周するたびに生成と破棄を繰り返します。ですので、アプリケーション終了まで、オブジェクトが溜まっていくということはありません。たいていは、autorelease済みのオブジェクトはメソッドを抜けた後に解放されます。

ということでした。お詫びして訂正させていただきます。

詳細を知りたい方は、『高度なメモリ管理プログラミングガイド』に難解な説明がありますので参照してください。

実際のmain()関数では

NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];

でNSAutoreleasePoolのインスタンス『pool』を生成/初期化、つまりプールを設置し、

[pool release];

でプールを解放します。


2-4)UIApplicationMain()関数の呼び出し

実際にアプリケーションの初期化を行うのがUIApplicationMain()関数で、UIApplicationのインスタンスを生成します。


UIApplicationMain

int UIApplicationMain (
    int argc,
    char *argv[],
    NSString *principalClassName,
    NSString *delegateClassName
);

main()関数が呼び出す、アプリケーションオブジェクトとアプリケーションデリゲートの生成、アプリケーションの実行ループを含むイベントループの設定を行う関数です

戻り値はint型(整数)を指定していますが、この関数は戻り値を返しません

ユーザがホームボタンを押してiPhoneアプリケーションを終了させた時、0の引数と終了システム関数を呼び、アプリケーションはすぐに終了します

アプリケーションのInfo.plistファイルで、NSMainNibFileキーに対応するnibファイルが設定されていれば、このnibファイルを読み込みます

argc:第2引数argvの項目数を指定します
通常はmain()関数から引き継ぎます

argv:引数の配列を指定します
通常はmain()関数から引き継ぎます

principalClassName:UIApplicationクラスまたはサブクラスの名前を指定します
nilの場合はUIApplicationとなります

delegateClassName:アプリケーションデリゲートをインスタンス化するクラス名を指定します
principalClassNameでUIApplicationのサブクラスを指定した場合、サブクラスのデリゲートを指定する必要が有ります
nilの場合は、アプリケーションのメインnibファイルからデリゲートオブジェクトを読み込みます


デフォルトでは第3、第4引数ともにnilが指定されていますので、UIApplicationクラスでアプリケーションオブジェクトが、第4引数でInfo.plistの『Main nib file base name』に設定されているnibファイル

222

この場合MainWindow.xibファイルで設定されていますので、開いてみると

221

Untitled App Delegateというデリゲートが作られていることになります。


2-5)アプリケーションデリゲートの作成

当サイトでも何度か取り上げつつ理解していないデリゲートですが、そろそろ覚えたいので説明してみます。

デリゲートは日本語では代理、委託、委譲などと訳されるもので、メッセージを受けたオブジェクトが自分で処理できない、あるいは少し細工を加えて処理したい場合にデリゲートオブジェクトに処理を頼むという仕組みです。

自分で処理できないメッセージを託すのは、例えばボタンのオン/オフを表示するオブジェクトが操作の是非を判断する場合など、本業以外はデリゲートに任せ独立性を保持する意味があります。

少し細工を加えて処理するのも同様で、自分が持っていない機能の指示を一緒に渡して処理してもらうことで、複雑なオブジェクトのサブクラス化を避ける意味があります。

デリゲートは開発者が任意の位置に配置できますが、UIApplicationMain()関数で設定されるアプリケーション固有のデリゲートをアプリケーションデリゲートと言います。

アプリケーションデリゲートは全てのアプリケーションに必須ですが、テンプレートでプロジェクトを作成すると自動で~AppDelegate.mと~AppDelegate.hが作られます。 

(正確には上記のようにMainWindow.xibファイルで登録されている~App Delegateがアプリケーションデリゲートとなります)

この中にアプリケーションの初期実行状態にする準備と、終了時に未保存データやアプリケーションの状態を保存する処理などを記述します。

アプリケーションデリゲートのオブジェクトはUIApplicationDelegateプロトコルを採用している必要が有ります。


2-6)UIApplicationDelegateプロトコル

UIApplicationDelegateプロトコルは、シングルトンのUIApplicationオブジェクトのデリゲートを宣言するメソッドです。
(シングルトンはインスタンスを一つしか作らないクラスのことで、何処で何回呼ばれても同じインスタンスを返します)

このメソッドを実行すると、アプリケーションの起動と終了、メモリ不足の警告、URLリソースを開く、ステータスバーの向きの変更などシステムイベントにデリゲートが応答できるようになります。

iPhone OS 3.0では、リモート通知関連のメソッドやapplication:didFinishLaunchingWithOptions:を追加しました。

application:didFinishLaunchingWithOptions:メソッドはapplicationDidFinishLaunching:の代わりに呼び出すことができます。

これらの新しいメソッドは次の二つの状況を想定しています。

・iPhone OSがアプリケーションにリモート通知を配信し、ユーザがその通知に応答して起動する
・UIApplicationのopenURL:メソッドで、URLのスキーム(リソースを取得する手段)からリソースタイプを判別して他のアプリケーションを起動する

通常の場合は起動する理由が異なるので、別のユーザインターフェイスでアプリケーションを選択します。

UIApplicationは、application:didFinishLaunchingWithOptions:のオプションで指定されている辞書(NSDictionaryオブジェクト)を渡します。

アプリケーションを起動する要因となる辞書には二つ有り、一つはopenURL:メソッドを呼び出したアプリケーションのバンドルID(バンドル識別子)かURLオブジェクトを含む辞書、もう一つはリモート通知に含まれるペイロードの辞書です。

このメソッドがデリゲートを作る場合、起動時に以下の順序で呼び出されます

application:didFinishLaunchingWithOptions:
applicationDidBecomeActive:

代替として

applicationDidFinishLaunching:
applicationDidBecomeActive:
application:handleOpenURL:(アプリケーションの起動にURLが使われている場合)

同様に、プッシュ通知を受けてアプリケーションを起動させる際に、application:didFinishLaunchingWithOptions:メソッドとapplication:didReceiveRemoteNotification:メソッドの両方を実装すると、後者のメソッドは実行されません。

双方の場所でリモート通知を処理する必要があります。


2-7)~AppDelegateの宣言と実装

Window-based ApplicationのUntitledというプロジェクトを例に、アプリケーションデリゲートの内容を見てみます。


・UntitledAppDelegate.h

224

// UIKitフレームワークのインポート
#import <UIKit/UIKit.h>

// UntitledAppDelegateのクラス宣言(UIApplicationDelegateプロトコルの採用)
@interface UntitledAppDelegate : NSObject <UIApplicationDelegate> {

// このアプリケーションで使うウィンドウのインスタンス変数の宣言
    UIWindow *window;
}

// ウィンドウのインスタンス変数のプロパティを宣言
@property (nonatomic, retain) IBOutlet UIWindow *window;

@end

@interfaceでUntitledAppDelegateのクラス宣言しています。

スーパークラスはNSObjectですが、UIApplicationDelegateプロトコルを採用しなければならいので<>で追加しています。
(『Objective-C言語のメモ書き(4)』参照)

プロパティの属性はnonatomic(非同期)、retain(値を保持して変更)。

IBOutletはInterface Builderへ接続するためのキーワードで、アウトレットとして扱うことを指します。
(『Objective-C言語のメモ書き(5)』参照)


・UntitledAppDelegate.m

223

// ヘッダファイルの読み込み
#import "UntitledAppDelegate.h"

// ヘッダファイルで宣言した、UntitledAppDelegateクラスの実装
@implementation UntitledAppDelegate

// ヘッダファイルで宣言した、windowプロパティの実装
@synthesize window;

// アプリケーション起動直後の処理
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {

    // Override point for customization after application launch
    // アプリケーション起動後にカスタマイズする場合、上書きする内容を記述する

    // ウィンドウの表示
    [window makeKeyAndVisible];

    return YES;
}

- (void)dealloc {

    // ウィンドウオブジェクトの解放
    [window release];

    // スーパークラス(NSObject)の解放
    [super dealloc];
}

※ deallocインスタンスメソッドについては、後日理解した際に説明したいと思います。


・application:didFinishLaunchingWithOptions:

- (BOOL)application:(UIApplication *)applicationdidFinishLaunchingWithOptions:(NSDictionary *)launchOptions

リモート通知やURLリソースを開くことにより、アプリケーションが起動することをデリゲートに伝えます

アプリケーションがURLリソースを処理できなかった場合はNO、処理できた場合はYESを返します。

リモート通知の結果によってアプリケーションが起動した場合は、この戻り値は無視されます。

(次の文は上手く訳せなかったので原文を転載します)
Objects that are not the application delegate can access the same launchOptions dictionary values by observing the notification named UIApplicationDidFinishLaunchingNotification and accessing the notification’s userInfo dictionary.

applicationDidFinishLaunchingの代わりに、このメソッドを使用することを推奨します。
(2つの解説を見比べて下さい)

application:デリゲートするアプリケーションオブジェクト指定します

launchOptions:次の2つの状況に関連する情報を含む辞書を指定します

・iPhone OSがアプリケーションにリモート通信を配信し、警告メッセージの表示を経てアプリケーションを起動する場合

・URLのリソースをスキームで判別し、他のアプリケーションを開く場合

前者の場合、launchOptionsの辞書は、通知ペイロードの辞書を含みます。
(詳細は『UIApplicationDelegate Protocol Reference/application:didReceiveRemoteNotification:』を参照)

後者の場合、launchOptionsの辞書は、URLの示すオブジェクトと、URLが開こうとしているアプリケーションのバンドル識別子を含みます。

この辞書は、ユーザがアプリケーションのアイコンをタップして起動した場合はnilになります。

詳細はUIApplication Class Referenceの『UserInfo Dictionary Keys』に、これらの辞書オブジェクトのキーやアクセス方法の説明があります。


・makeKeyAndVisible

- (void)makeKeyAndVisible

キーウィンドウを作成して描画します

これは便利なメソッドで、レシーバのメインウィンドウを作成し、他のウィンドウより前に表示します

UIViewプロパティのhiddenを使ってウィンドウを隠すこともできます



参考文献

iOSアプリケーションプログラミングガイド

高度なメモリ管理プログラミングガイド

LocalおよびPush Notificationプログラミングガイド

NSAutoreleasePool Class Reference

UIKit Function Reference

UIApplicationDelegate Protocol Reference

UIWindow Class Reference

サルにもできるiPhoneアプリの作り方Step2/Objective-C入門

初心者のためのポイント学習C言語/コマンドライン引数

Wikipedia/スキーム

IT用語辞典/ペイロード

iPhone SDK 3 プログラミング大全 実践プログラミング (MacPeople Books)iPhone SDK 3 プログラミング大全 実践プログラミング (MacPeople Books)
(2009/09/08)
木下 誠

商品詳細を見る

詳解 Objective-C 2.0 第3版詳解 Objective-C 2.0 第3版
(2011/12/28)
荻原 剛志

商品詳細を見る






QuietControl 30 wireless headphones
0 Comments
Leave a comment
管理者にだけ表示を許可する
Top
0 Trackbacks
Top
Calendar
04 | 2017/05 | 06
Sun Mon Tue Wed Thu Fri Sat
- 1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30 31 - - -
Recent Articles
iTunes


Swift
Categories
Tips
Profile

水月杏香

Author:水月杏香
永遠の初心者プログラマ。

Wish List
WACOM


ARC
Technical Q&A
情報プロパティリストキー
Start Developing iOS Apps Today
BOSE

QuietControl 30 wireless headphones
Reference
NSApplicationDelegateプロトコル
NSArrayクラス
NSAutoreleasePoolクラス
NSBundleクラス
NSBundle UIKit追加分
NSCalendarクラス
NSCoderクラス
NSCodingプロトコル
NSCopyingプロトコル
NSDataクラス
NSDateクラス
NSDateFormatterクラス
NSDictionaryクラス
NSEntityDescriptionクラス
NSEnumeratorクラス
NSErrorクラス
NSExceptionクラス
NSFetchRequestクラス
NSFileHandleクラス
NSFileManagerクラス
NSIndexPathクラス
NSIndexPath UIKit追加分
NSKeyedArchiverクラス
NSKeyedUnarchiverクラス
NSKeyValueCodingプロトコル
NSLocaleクラス
NSManagedObjectクラス
NSManagedObjectContextクラス
NSManagedObjectModelクラス
NSMutableArrayクラス
NSMutableCopyingプロトコル
NSMutableDictionaryクラス
NSMutableSetクラス
NSNotificationクラス
NSNotificationCenterクラス
NSNullクラス
NSNumberクラス
NSObjectクラス
NSObject UIKit追加分
NSObjectプロトコル
NSPersistentStoreクラス
NSPersistentStoreCoordinatorクラス
NSPredicateクラス
NSPropertyListSerializationクラス
NSRunLoopクラス
NSSetクラス
NSStringクラス
NSString UIKit追加分
NSTimerクラス
NSTimeZoneクラス
NSURLクラス
NSURLProtectionSpaceクラス
NSURLRequestクラス
NSUserDefaultsクラス
NSValueクラス

UIActionSheetクラス
UIActionSheetDelegateプロトコル
UIActivityIndicatorViewクラス
UIAlertViewクラス
UIAlertViewDelegateプロトコル
UIApplicationクラス
UIApplicationDelegateプロトコル
UIBarButtonItemクラス
UIBarItemクラス
UIButtonクラス
UIColorクラス
UIControlクラス
UIDatePickerクラス
UIDeviceクラス
UIEventクラス
UIFontクラス
UIGestureRecognizerクラス
UIImageクラス
UIImageViewクラス
UIKit Function
UILabelクラス
UINavigationControllerクラス
UINavigationItemクラス
UIPickerViewクラス
UIPickerViewDataSourceプロトコル
UIPickerViewDelegateプロトコル
UIPinchGestureRecognizerクラス
UIResponderクラス
UIScreenクラス
UIScrollViewクラス
UISearchBarクラス
UISearchBarDelegateプロトコル
UISegmentedControlクラス
UISliderクラス
UISwipeGestureRecognizerクラス
UISwitchクラス
UITableViewクラス
UITableViewCellクラス
UITableViewControllerクラス
UITableViewDataSourceプロトコル
UITableViewDelegateプロトコル
UITapGestureRecognizerクラス
UITextFieldクラス
UITextFieldDelegateプロトコル
UITextInputTraitsプロトコル
UITextViewクラス
UITextViewDelegateプロトコル
UIToolbarクラス
UITouchクラス
UIViewクラス
UIViewControllerクラス
UIWebViewクラス
UIWebViewDelegateプロトコル
UIWindowクラス

AVAudioPlayerクラス
AVAudioPlayerDelegateプロトコル

CADisplayLinkクラス
CAEAGLLayerクラス
CALayerクラス

CGAffineTransform
CGBitmapContext
CGColor
CGColorSpace
CGContext
CGGeometry
CGImage
CGPath

EAGLContextクラス
EAGLDrawableプロトコル

Foundation Constants
Foundation Data Types
Foundation Functions

MPMediaItemクラス
MPMediaItemArtworkクラス
MPMediaPlaylistクラス
MPMediaPropertyPredicateクラス
MPMediaQueryクラス
MPMusicPlayerControllerクラス

Randomization Services

System Sound Services
Amazon


OpenGL ES
SQLite
Monthly Archives
Recent Comments
Recent TrackBacks
RSS Link
Visitors
QR Code
QR