Xcode 3.2.6から4.6.2でのテンプレートの変化(2)〜AppDelegate

2013. 05. 28
旧版のアプリケーションデリゲートクラスにはプロジェクト名の接頭辞が付くのでHelloWorldAppDelegateになっています。

また『初めてのiOSプログラミング 第2版』ではストーリーボードを使用していないので、新版のプロジェクトは基本的に『ARC:オン/ストーリーボード:オフ』のものとなります。

ただし『ARC:オン/ストーリーボード:オン』や『ARC:オフ/ストーリーボード:オフ』のプロジェクトとの差異がある場合は、それついても補足します。



●ARCやストーリーボードの利用の可否

ARCは、既存のプロジェクトを継続して開発する、あるいは過去の非ARCライブラリを活用するなど必要性がある場合を除き、新規開発であれば標準で利用するものと思って良いでしょう。

ストーリーボードに関しては、既存のプロジェクトとの互換性から利用しない(できない)、nibファイルまたはコードでUIを構築するので必要としないなど、必ずしも優先的に利用を推奨するものではないようです。

ですが『初めてのiOSアプリケーション』でもストーリーボードを利用しているように、今後標準となる機能でしょうから、特段の理由やこだわりが無いのであれば活用すると良いでしょう。



●AppDelegate.hの比較

旧版と新版のAppDelegate.hのコードを比較します。

旧版)

#import <UIKit/UIKit.h>

@class HelloWorldViewController;

@interface HelloWorldAppDelegate : NSObject <UIApplicationDelegate> {
    UIWindow *window;
    HelloWorldViewController *viewController;
}


@property (nonatomic, retain) IBOutlet UIWindow *window;
@property (nonatomic, retain) IBOutlet HelloWorldViewController *viewController;

@end

新版)

#import <UIKit/UIKit.h>

@class ViewController;

@interface AppDelegate : UIResponder <UIApplicationDelegate>

@property (strong, nonatomic) UIWindow *window;

@property (strong, nonatomic) ViewController *viewController;

@end


1)スーパークラスの変更

アプリケーションデリゲートクラスのスーパークラスが、旧版ではNSObjectですが新版ではUIResponderになっています。

この理由は『ストーリーボードへの変換のリリースノート』の『アプリケーションデリゲートの構成』で以下のように説明されています。

『現在のXcodeテンプレートでは、アプリケーションデリゲートクラスはUIResponderを継承しています。
これはデリゲートのインスタンスがレスポンダチェーンに参加し、アプリケーションレベルのアクションの処理ができるようにするためです。
既存のアプリケーションでこのパターンの使用を用いていない場合、ストーリーボードのために採用する必要はありません。』



2)インスタンス変数の宣言の削除

旧版では宣言済みプロパティのインスタンス変数を宣言していますが、新版では宣言が削除されています。

これは『cockscomb.info/イマドキっ子の Objective-C』でも指摘されているように、『Objective-Cプログラミング言語』のp.38で以下のように説明されています。

『インスタンス変数は実装詳細であり、通常、クラス自身の外からアクセスされることはありません。さらに、実装ブロック内に宣言すること、あるいは宣言済みプロパティから自動生成させることも可能です。したがって通常は、インスタンス変数宣言をパブリックインターフェイスで行うべきではないので、波括弧も省略してください。』

つまり、クラス内部でしか使用しないインスタンス変数をヘッダファイルで宣言することは、必要なインターフェイスのみ公開するというカプセル化(情報隠蔽)に反するので止めようということです。

したがって必要なインスタンス変数はソースファイルで宣言することになります。


3)宣言済みプロパティの属性の変更

宣言済みプロパティの属性がretainからstrongに変更されています。

これはARC導入に因るものです。

ARCについては『What's New in iOS〜iOS 5.0〜自動参照カウント』や『ARCへの移行のリリースノート』を参照してください。


4)IBOutlet識別子の削除

旧版では宣言済みプロパティの宣言にIBOutlet識別子が挿入されていますが、新版では削除されています。

旧版はウィンドウおよびビューコントローラのインスタンスをnibファイル(MainWindow.xibとHelloWorldViewController.xib)で生成・初期化しているため、IBOutletで接続する必要があります。

しかし新版ではAppDelegate.mのapplication:didFinishLaunchingWithOptions:メソッド内で生成・初期化しているため、その必要がありません。



●AppDelegate.mの比較

旧版と新版のAppDelegate.mのコードを比較します。

旧版)

#import "HelloWorldAppDelegate.h"
#import "HelloWorldViewController.h"

@implementation HelloWorldAppDelegate

@synthesize window;
@synthesize viewController;


- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {

    self.window.rootViewController = self.viewController;
    [self.window makeKeyAndVisible];

    return YES;
}

- (void)applicationWillResignActive:(UIApplication *)application {
}

- (void)applicationDidEnterBackground:(UIApplication *)application {
}

- (void)applicationWillEnterForeground:(UIApplication *)application {
}

- (void)applicationDidBecomeActive:(UIApplication *)application {
}

- (void)applicationWillTerminate:(UIApplication *)application {
}

- (void)applicationDidReceiveMemoryWarning:(UIApplication *)application {
}

- (void)dealloc {
    [viewController release];
    [window release];
    [super dealloc];
}


@end

新版)

#import "AppDelegate.h"
#import "ViewController.h"

@implementation AppDelegate

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
    self.viewController = [[ViewController alloc] initWithNibName:@"ViewController" bundle:nil];

    self.window.rootViewController = self.viewController;
    [self.window makeKeyAndVisible];
    return YES;
}

- (void)applicationWillResignActive:(UIApplication *)application
{
}

- (void)applicationDidEnterBackground:(UIApplication *)application
{
}

- (void)applicationWillEnterForeground:(UIApplication *)application
{
}

- (void)applicationDidBecomeActive:(UIApplication *)application
{
}

- (void)applicationWillTerminate:(UIApplication *)application
{
}

@end


1)@synthesizeの削除

旧版ではヘッダファイルで宣言している宣言済みプロパティ(windowとviewController)を@synthesizeで実装していますが、旧版では削除されています。

これは『頭と尻尾はくれてやる!/Xcode 4.4でさよなら@synthesize』でも指摘されているように、『Xcode 4.4の新機能』の『Objective-C言語の機能』で以下のように説明されています。

『Objective-Cの@propertiesは、明示的に実装されていない時はデフォルトで合成されます。』

『デフォルトの@synthesize機能は、特別なSDKやランタイムサポートを必要としません。』


つまりXcode 4.4以降でプロジェクトを作成する場合、プログラマが手動によって@synthesizeを記述しない場合はコンパイラが自動でコード補完して合成するので、記述が不要になるということです。


2)プロパティのインスタンス変数の命名規則

新版のコードでは@synthesize文が省略されていますが、『初めてのiOSプログラミング 第2版』本文中のコードには@synthesize文があります(翻訳時はXcode 4.5ですが、原著はXcode 4.3.2のため)。

そこでは宣言済みプロパティのインスタンス変数名として、プロパティ名の頭にアンダースコアが付加されています。

Cocoa向け コーディングガイドライン』の改訂履歴を見ると、2012年2月16日の改訂で、

『ivar名に適した接頭辞は「_」であるという注釈を付記しました。』

とあるので、同日にリリースされたXcode 4.3による改訂かと思いましたが、2011年12月14日に発行されている『Start Developing iOS Apps Today』の補足『Start Developing iOS Apps Today(sup.2)〜Objective-Cコードの記述』の中で、

『インスタンス変数はプロパティとして同じ名前を持ちますが、アンダースコア接頭辞(_)を持ちます。』

とあるので、Xcode 4.3以前からということが分かります。

「よくわかるiPhoneアプリ開発の教科書」サポートサイト』の『補足情報(2012/05/24)』によると、

『これは、Xcode 4.2の自動生成から出るようになったもので、FilpsideViewController.mの最初の方で、
 @synthesize mySw = _mySw;
と指定されているものです。』


とあるので、Xcode 4.2からの自動生成でインスタンス変数名にアンダースコアが付くようになったようです。

アプリ開発記/Objective-Cの@synthesizeについて』で紹介されているように、『Objective-Cによるプログラミング』のp.47『プロパティの多くはインスタンス変数を使って実装されている』において、

『特に指定しなければ、このインスタンス変数の名前は、プロパティ名の先頭にアンダースコアを置い たものになります。たとえば、「firstName」というプロパティに対応するインスタンス変数は、 「_firstName」となります。
(中略)
アンダースコアがついているので、たとえば局所変数ではなく、インスタンス変数 であることがひと目で分かります。』


とあり、『Cocoa向け コーディングガイドライン』のp.21『プロパティ(Declared Property)とインスタンス変数』では、その理由の一端も説明されています。

『通常、インスタ ンス変数に直接アクセスすることはなく、アクセサメソッドを使用します(initメソッドとdealloc メソッドでは直接インスタンス変数にアクセスします)。これを効果的にシグナリングするために、 以下のようにインスタンス変数名の接頭辞にアンダースコア(_)を使います。』

かつては『GLFun(12)~Texture2Dクラス(1)』の『3)クラスのインターフェイス』で説明しているように、アンダースコアで始まる接頭辞はAppleが予約しているので使用禁止のはずでした。

現在は『Cocoa向け コーディングガイドライン』のp.9『表記規約』において、

『メソッド名に、プライベートを意味するプレフィックスとしてアンダースコア文字を使用することは避けてください(インスタンス変数名に、プレフィックスとしてアンダースコア文字を使用することは可能です)。この命名規約は、Appleにより使用されるものとして予約されています。』

と、インスタンス変数名に関しては制限が解除されたようです。

この辺に関しては、『Awaresoft/プロパティに対応するインスタンス変数の命名規則について』で非常に分かり易く解説されていますので、参照してください。


3)ウィンドウとビューコントローラのインスタンスの生成・初期化の差異

旧版のapplication:didFinishLaunchingWithOptions:メソッド内では、ビューコントローラのインスタンスをルートビューコントローラに設定し、キーウィンドウの設定とウィンドウの表示を行っています。

新版ではその処理の前にウィンドウとビューコントローラのインスタンスを生成・初期化を行っています。

これは『Xcode 3.2.6から4.6.2でのテンプレートの変化(1)〜main.m』の『3)UIApplicationMain関数の第4引数の指定』で説明しているように、ストーリーボード使用時の場合との互換性を保つため、ストーリーボード非使用時も一貫してアプリケーションデリゲートクラスでウィンドウとビューコントローラの生成・初期化を行っているものと思われます。
(『ストーリーボードへの変換のリリースノート』を参照してください。)

旧版ではウィンドウのインスタンスは、アプリケーションのメインnibファイルとしてHelloWorld-Info.plistのMain nib file base name(NSMainNibFileキー)で指定されているMainWindow.xibから生成・初期化され、IBOutlet識別子によってwindowプロパティと接続されます。

しかし新版ではHelloWorld-Info.plistにNSMainNibFileキーの指定が無く、MainWindow.xibも存在しないため、コードで生成・初期化を行っています。

ビューコントローラは、旧版ではMainWindow.xibから接続されているHelloWorldViewController.xibで生成・初期化されますが、新版ではコードでViewController.xibを読み込んで生成・初期化を行っています。


4)applicationDidReceiveMemoryWarning:メソッドの削除

旧版では自動生成されているapplicationDidReceiveMemoryWarning:メソッドが、新版では削除されています。

iOSアプリケーションプログラミングガイド』のp.134『メモリ不足警告を監視する』においても、その必要性は説明されているので削除された理由は分かりませんが、実際に開発を行う際には忘れずに実装するようにしましょう。


5)deallocの削除

What's New in iOS〜iOS 5.0〜自動参照カウント』や『ARCへの移行のリリースノート』で説明されているように、ARCを導入した場合はコンパイラが適切なdeallocメソッドを自動生成するため、(インスタンス変数以外のリソースを解放する必要がある場合を除き)deallocメソッドの呼び出しは禁止されています。



●ARC:オフ/ストーリーボード:オフの場合

#import "AppDelegate.h"
#import "ViewController.h"

@implementation AppDelegate

- (void)dealloc
{
    [_window release];
    [_viewController release];
    [super dealloc];
}


- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    self.window = [[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]] autorelease];
    self.viewController = [[[ViewController alloc] initWithNibName:@"ViewController" bundle:nil] autorelease];
    self.window.rootViewController = self.viewController;
    [self.window makeKeyAndVisible];
    return YES;
}

- (void)applicationWillResignActive:(UIApplication *)application
{
}

- (void)applicationDidEnterBackground:(UIApplication *)application
{
}

- (void)applicationWillEnterForeground:(UIApplication *)application
{
}

- (void)applicationDidBecomeActive:(UIApplication *)application
{
}

- (void)applicationWillTerminate:(UIApplication *)application
{
}

@end

ARCをオフにした場合、AppDelegate.mにdeallocメソッドが実装されます。

またapplication:didFinishLaunchingWithOptions:メソッドで生成・初期化しているウィンドウとビューコントローラのインスタンスは、autoreleaseメソッドで自動解放プールに追加されています。



●ARC:オン/ストーリーボード:オンの場合

ストーリーボードを導入した場合、HelloWorld-Info.plistのMain storyboard file base name(UIMainStoryboardFileキー)でMainStoryboard.storyboardファイルが指定され、ウィンドウとビューコントローラの生成・初期化がストーリーボードで行われます。

これに伴い、アプリケーションデリゲートクラスのコードも変わります。


1)AppDelegate.h

#import <UIKit/UIKit.h>

@interface AppDelegate : UIResponder <UIApplicationDelegate>

@property (strong, nonatomic) UIWindow *window;

@end

宣言済みプロパティはウィンドウだけで、ビューコントローラは宣言していません。


2)AppDelegate.m

#import "AppDelegate.h"

@implementation AppDelegate

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    return YES;
}

- (void)applicationWillResignActive:(UIApplication *)application
{
}

- (void)applicationDidEnterBackground:(UIApplication *)application
{
}

- (void)applicationWillEnterForeground:(UIApplication *)application
{
}

- (void)applicationDidBecomeActive:(UIApplication *)application
{
}

- (void)applicationWillTerminate:(UIApplication *)application
{
}

@end

application:didFinishLaunchingWithOptions:メソッドでの、ウィンドウとビューコントローラのインスタンスの生成・初期化が無くなっています。

またnibファイルとは異なり、ストーリーボードでは(rootViewControllerプロパティによる)ルートビューコントローラの設定と、(makeKeyAndVisibleメソッドによる)ウィンドウの可視化も行われるようです。



参考文献

Apple/Objective-Cプログラミング言語

Apple/Cocoa向け コーディングガイドライン

Apple/Objective-Cによるプログラミング

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

cockscomb.info/イマドキっ子の Objective-C

頭と尻尾はくれてやる!/Xcode 4.4でさよなら@synthesize

「よくわかるiPhoneアプリ開発の教科書」サポートサイト

アプリ開発記/Objective-Cの@synthesizeについて

『Objective-Cプログラミング THE BIG NERD RANCH GUIDE』サポートページ/訳者補記1 Xcode 4.4のリリース時にObjective-Cに追加された機能

Awaresoft/プロパティに対応するインスタンス変数の命名規則について

初めてのiOSプログラミング 第2版初めてのiOSプログラミング 第2版
(2012/10/20)
Alasdair Allan

商品詳細を見る






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