OS X で、複数の id_rsa を生成・管理するメモ

JUGEMテーマ:コンピュータ


GitHub(とか、Gitとか)から、そろそろ逃げていても仕方が無いな。と思って、ひとまずGitHubにアカウントつくりました。あー。面倒くさいけど、勉強しておかないとだめなんだろうなあ、Git。ユニットテストとか、Gitとか、Capistranoとか、この手の話はすごく苦手なんだけど、徐々に苦手意識なくして、がんばらねばなあ。。と、グチはさておき。GitHub使うにあたって、SSH public key(RSA)の登録が必要だったので、メモ。

SSH Key は、外部のサーバに接続する際などで利用されてますよね。ぱんも、自分で管理しているサーバの「sshd_config」で、RSAAuthentication を有効にしています。一つのSSH Key を、いろんなサービスで使い回してもいいのかもしれないんですが、よくわからなくなると嫌なので、案件ごとにSSH Key を作成・管理したいと思います。

1)現在SSHキーが存在している場合、ファイル名を変更します;
・「 $ ls -la ~/.ssh 」で内容を確認し。
・「id_rsa」を「id_rsa.◯◯◯◯」に変更。
・「id_rsa.pub」を「id_rsa.pub.◯◯◯◯」に変更。
※「◯◯◯◯」は、任意の半角英数字


2)「$ touch ~/.ssh/config 」で設定ファイルを生成し、内容を以下のとおりとします;
-------
 Host ◯◯◯◯
HostName ◯◯◯◯
IdentityFile ~/.ssh/id_rsa.◯◯◯◯
User ◇◇◇◇
-------
→そのサーバに接続する際は、$ ssh ◯◯◯◯ とすればOK。



3)新しいSSH Keyを作成します;
・「 $ ssh-keygen -t rsa -C "xxxxxx@xxxxx.com" 」

4)「3」についても「1」と同じ用にリネームし、「2」のファイルを;
-------
 Host ◯◯◯◯
HostName ◯◯◯◯
IdentityFile ~/.ssh/id_rsa.◯◯◯◯
User ◇◇◇◇
 Host ◎◎◎◎
HostName ◎◎◎◎
IdentityFile ~/.ssh/id_rsa.◎◎◎◎
User □□□□
-------
のように、追加編集します。

◎◎◎◎に接続したい場合は;
→ $ ssh ◎◎◎◎ とすればOK。


以上。シンプルながら、便利ですね。


▼参考サイト)
Set Up Git 〜GitHub〜
~/.ssh/config で簡単に複数ホストへのSSH接続を管理する
SSH-KEYGEN (1) 〜Open SSH マニュアル翻訳〜

「突拍子もない」わけではない。〜 Infinite loop の話 〜

JUGEMテーマ:コンピュータ



ちょっと前に発表された、Appleの新本社についての感情を、うまく表現できなかったんだけれども。現在のApple本社をgoogle mapで見て、ようやく言いたいことが自分でもわかった。


▼ 現在の Apple 本社
apple 本社
Google Map で見る

▽ iOS の、Map App アイコン(本社所在地をアイコン化)



▼ 計画中の Apple 本社
Apple 本社・未来
計画の概要(Tech Crunch Japan)

▽ ジョブズの、市関係者に向けたプレゼン




現在の本社「Infinite loop(無限ループw)」は、ジョブズがいない間に計画・建設されたものだ。でも、この形は、計画中の宇宙船型・新本社につながるコンセプトを持っている。テッククランチのコメント欄では「箱モノ=NG」的なものも見受けられるけれど、Appleのプロダクトの魅力は、外見と内蔵物の見事な融合にあるのだから、個人的にはこの新本社、いいと思うけれどもなあ。。

コンピュータやってる会社が、本社に「無限ループ(→ Wikipedia)」ってするのは面白いなあ。

これが、ジョブズのセンスではない。という点が、もっと面白い。

Wikipediaの該当ページで[拡大]して見る。

Appleは、ジョブズがいなくなっても、意外と大丈夫なのではないかなあ。(ジョブズをリスペクトする身としては、彼のプロデュースした「Apple」という企業(文化)が、継続性のある(無限にループする)存在であってほしい、という希望的な意味も含めて。。。)



NeXT, Inc.をつくったころから、ジョブズはずっと気になる存在だった。そしていまになって、iOSのアプリを作るために、「NS◯◯(NSは、NeXTSTEP(NeXTのOS)の頭文字をとったもの)」みたいなObjective-Cのコードを勉強している。なんだか、時間軸が、止まっている。というか、ループしている。これが、Infinite loop なのかも。


何がいいたいか、わかりづらいエントリーになっちゃいましたが。。 要するに「Appleの今の形も、未来の形も、予め定義されている無限ループの中にあるようだ。」ということが言いたいのです。いまはまだうまく表現できないけれど。うまく表現できるようになったら、またエントリーします。

『iOS Core Dataチュートリアル』を、Xcode4.2 + Lion で学ぶ。

JUGEMテーマ:コンピュータ


iOSで、データの保存/参照/変更/削除を行う場合、CoreDataを使うらしい。という情報を得て、いいチュートリアルが無いか探しました。Appleが提供しているチュートリアルで、日本語訳されているものがあったので、それを使うことにします。2010年末のドキュメントなので、例によってXcode4.2で使う場合には、幾つかの苦難が待ち受けていることが予想されます。。



それではまず、チュートリアルをダウンロードします。Appleの公式ドキュメントの日本語訳は「iOS Developer Library」にあります。古い情報が多いですが、定期的に「これは!」とアップルが思うドキュメントを追加/更新しているようです。RSSも購読可能なので、ぱんは登録してウォッチしています。

今回利用するチュートリアルは下記となります;
【PDF】『iOS Core Dataチュートリアル 〜Core Data Tutorial for iOS〜』



1)プロジェクトの作成(P.10)
・Xcodeを起動します。

Empty Application 選択
・「Empty Application」テンプレートを選択し「Next」。


・「Product Name」を「Locations」。「Class Prefix」にも「Locations」を入力。「Use Core Data」のチェックボックスをチェックし「Next」。

・保存先を適当に指定して「Create」。


2)「CoreLocation」フレームワークへのリンク設定(P.10)
・「Locations」を起動した際の初期画面にある、ヘッダナビゲーションの「Build Phases」をクリック。



・「Link Binary With Libraries」を開いて、その左下コーナーに現れる「+」をクリック。
・「CoreLocation.framework」を選択し、「Add」。


3)RootViewControllerクラスの作成(P.17)
・Xcodeメニュー「File >New >New File...」を選択。


・開いたウインドウの、左ペイン「iOS」の「Cocoa Touch」を選択し、右ペイン「UIViewController」を選択し、「Next」。


・「Class」を「RootViewController」と入力し、「With XIB for user interface」のチェックボックスのチェックが外れていることを確認して、「Next」。
・開いたダイアログの右下にある「Create」をクリック。


4)RootViewController.h の編集(P.18)
▼下記コードに、内容を書き換える
-------
#import <CoreLocation/CoreLocation.h> //「<」「>」は半角で

// クラス宣言→ @interface クラス名:スーパークラス <デリゲート(指定した別のクラスにメッセージを丸投げできるよう設定する)>
@interface RootViewController : UITableViewController <CLLocationManagerDelegate> { //「<」「>」は半角で
// インスタンス変数の宣言
NSMutableArray *eventsArray; // イベント配列
NSManagedObjectContext *managedObjectContext; // 管理オブジェクトコンテキスト
CLLocationManager *locationManager; // Core Locationマネージャ
UIBarButtonItem *addButton; // 追加ボタン
}
// メソッドの宣言(ここでは、setter & getterを作るオマジナイを記述)
@property (nonatomic, retain) NSMutableArray *eventsArray;
@property (nonatomic, retain) NSManagedObjectContext *managedObjectContext;
@property (nonatomic, retain) CLLocationManager *locationManager;
@property (nonatomic, retain) UIBarButtonItem *addButton;
@end

// ▼参考
//『Objective-CでのDelegateとは』 http://konton.ninpou.jp/program/cocoa/delegate.html
//『@propertyでnonatomic指定していいの?』 http://ringsbell.blog117.fc2.com/blog-entry-350.html
//『Objective-Cの @property と @synthesize の組み合わせが何をやっているのかを解説』 http://d.hatena.ne.jp/nakamura001/20101101/1288632739
-------


5)RootViewController.m に、setter & getter関連記述を追加(P.18〜19)
▼「@implementation RootViewController」の直下に下記コード追加;
-------
// setter & getter を作るオマジナイを記述
@synthesize eventsArray;
@synthesize managedObjectContext;
@synthesize locationManager;
@synthesize addButton;
//
// ▼参考
//『Objective-Cの @property と @synthesize の組み合わせが何をやっているのかを解説』
// → http://d.hatena.ne.jp/nakamura001/20101101/1288632739
-------


6)RootViewController.m に、「Core Locationマネージャ」を動的に作成するアクセサメソッドを作成(P.19)
▼「5」の直下に、下記コード追加;
-------
// インスタンスメソッド定義→ -(戻り値の型) メソッド名 : (引数の型) 引数名
- (CLLocationManager *)locationManager {
if (locationManager != nil) {
return locationManager;
}
locationManager = [[CLLocationManager alloc] init];
locationManager.desiredAccuracy = kCLLocationAccuracyNearestTenMeters;
locationManager.delegate = self;
return locationManager;
}
//
// ▼参考
//『メソッド呼びだし』 http://ja.wikipedia.org/wiki/Objective-C#.E3.83.A1.E3.82.BD.E3.83.83.E3.83.89.E5.91.BC.E3.81.B3.E3.81.A0.E3.81.97
//『メソッド定義とメッセージ式』 http://www.atmarkit.co.jp/fcoding/articles/objc/03/objc03b.html
//
//『CLLocationManager 〜iPhoneアプリ開発の虎の巻〜』 http://iphone-tora.sakura.ne.jp/cllocationmanager.html
//『<公式ガイド>位置情報対応プログラミングガイド』 http://developer.apple.com/jp/devcenter/ios/library/documentation/LocationAwarenessPG.pdf
//『GPSを利用する方法』 http://d.hatena.ne.jp/ntaku/20090228/1235816377
-------


7)RootViewController.m に、「追加(Add)」ボタンを状況に応じ、有効または無効にする2つのデリゲートメソッドを実装(P.19)
▼「6」の直下に、下記コード追加;
-------
- (void)locationManager:(CLLocationManager *)manager
didUpdateToLocation:(CLLocation *)newLocation
fromLocation:(CLLocation *)oldLocation {
addButton.enabled = YES;
}
- (void)locationManager:(CLLocationManager *)manager
didFailWithError:(NSError *)error {
addButton.enabled = NO;
}
//
// ▼参考
//『CLLocationで現在位置を取得する』http://iphone-app-developer.seesaa.net/article/128902019.html
-------


8)RootViewController.m に、「viewDidLoad」メソッドを実装(P.19〜20)
▼「7」の直下に、下記コード追加;
-------
- (void)viewDidLoad {
[super viewDidLoad];
// タイトルを設定
self.title = @"Locations";
//「Edit」ボタンのセットアップ
self.navigationItem.leftBarButtonItem = self.editButtonItem;
//「+」ボタンのセットアップ(非活性ボタンにして配置)
addButton = [[UIBarButtonItem alloc]
initWithBarButtonSystemItem:UIBarButtonSystemItemAdd
target:self action:@selector(addEvent)];
addButton.enabled = NO;
self.navigationItem.rightBarButtonItem = addButton;
// ロケーションマネージャを起動する。
[[self locationManager] startUpdatingLocation];
}
-------
※テンプレート標準の「viewDidLoad」メソッドのコメントアウト部分は、一律削除しておく


9)RootViewController.m に、「viewDidUnload」&「dealloc」メソッドを実装(P.20)
-------
- (void)viewDidUnload {
self.eventsArray = nil;
self.locationManager = nil;
self.addButton = nil;
}
- (void)dealloc {
[managedObjectContext release];
[eventsArray release];
[locationManager release];
[addButton release];
[super dealloc];
}
//
// ▼参考
//『UIViewController のメモリ管理まとめ』 http://hamasyou.com/blog/archives/000384
// → init で確保したメモリは dealloc で破棄する
// → viewDidload で確保したメモリは dealloc で破棄する。メモリ不足警告時には、didReceiveMemoryWarning メソッドから呼び出される、viewDidUnload で破棄する。
-------
※テンプレート標準の「viewDidUnload」メソッド関連の記述は、一律削除しておく


10)LocationsAppDelegate.h の編集(P.20)
▼下記コードに、内容を書き換える
-------
#import <UIKit/UIKit.h> //「<」「>」は半角で

// クラス宣言→ @interface クラス名:スーパークラス <デリゲート(指定した別のクラスにメッセージを丸投げできるよう設定する)>
@interface LocationsAppDelegate : UIResponder <UIApplicationDelegate> //「<」「>」は半角で

//『UIWindow 〜iPhoneアプリ開発の虎の巻〜』 http://iphone-tora.sakura.ne.jp/uiwindow.html
@property (strong, nonatomic) UIWindow *window;
@property (nonatomic, retain) UINavigationController *navigationController;

// 下記「▼参考」参照
@property (readonly, strong, nonatomic) NSManagedObjectContext *managedObjectContext;
@property (readonly, strong, nonatomic) NSManagedObjectModel *managedObjectModel;
@property (readonly, strong, nonatomic) NSPersistentStoreCoordinator *persistentStoreCoordinator;

- (void)saveContext;
- (NSURL *)applicationDocumentsDirectory;

@end

UINavigationController *navigationController;


// ▼参考
//『Core Data Overview : 重要なクラス』 http://blog.natsuapps.com/2010/09/core-data-overview_5352.html
//・「Managed Object Context」 http://cocoadevcentral.com/articles/000086.php#9
//・「Managed Object Model」 http://cocoadevcentral.com/articles/000086.php#3
//・「NSPersistentStoreCoordinator」http://cocoadevcentral.com/articles/000086.php#10
-------


11)LocationsAppDelegate.m に、ヘッダファイルのインポート追加&Navigation Controllerプロパティの合成(P.21)
▼「#import "LocationsAppDelegate.h"」の直下に、下記コード追加;
-------
#import "RootViewController.h"
-------
▼「@synthesize window = _window;」の直下に、下記コード追加;
-------
@synthesize navigationController;
-------


12)「- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{ }」の編集(P.21)
※ チュートリアル記載のコードのままでは、Xcode4.2 で動作しないので注意
▼ 下記内容に書き換える
-------
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
// チュートリアルでは削除されてるけど、ここの部分はXcode4.2の「Empty Application」テンプレートだと必須
self.window = [[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]] autorelease];

RootViewController *rootViewController = [[RootViewController alloc] initWithStyle:UITableViewStylePlain];
NSManagedObjectContext *context = [self managedObjectContext];
if (!context) {
// エラーを処理する
}
// 管理オブジェクトコンテキストをView Controllerに渡す
rootViewController.managedObjectContext = context;
UINavigationController *aNavigationController = [[UINavigationController alloc]
initWithRootViewController:rootViewController];
self.navigationController = aNavigationController;

//チュートリアルでは「window」だけど、「_window」に変更してます
[_window addSubview:[navigationController view]];
[_window makeKeyAndVisible];
[rootViewController release];
[aNavigationController release];
return YES;
}
-------


13)テストビルド実行
・特に問題なければ「Run」をクリックすると、開発途中のアプリのビューが表示されるはずです。

・でも、ぱんの環境では、原因不明のエラーが出ました。「This generally means that another instance of this process was already running or is hung in the debugger」というメッセージがデバッガーに表示されます。Terminalからアプリを消しても、改善されません。何度も同じプロジェクトをぐりぐりいじってたので、iPhoneシミュレータがうまく処理できなくなったようです。



・Mac自体を再起動してから、「Run」してiPhoneシミュレーターをみると、、、

iPhoneシミュレーター
・きちんと表示されました。

参考)http://ndevmemo.blog.shinobi.jp/Entry/83/
※ ちなみに、Lion+Xcode4.2の場合、iPhoneシミュレータが使うアプリは「 /Users/(ユーザ名)/Library/Application Support/iPhone Simulator/5.0/Applications/xxxxxxxxxxxx/ 以下に配置されています




14)CoreDataで「Event」エンティティを作成(P.23〜25)
・Xcodeの左カラムから「Locations.xcdatamodel」ファイルを選択


・メインカラムの下部「+ ( Add Entity)」をクリック
 → フォーカスされている「Entity」名に、「Event」と入力
・メインカラム「Attributes」コーナーの左下「+」をクリック
 → フォーカスされている「Attribute」名に、「creationDate」と入力
 → 「Type」の選択肢から、「Date」を選択
・再度、「+」をクリック
 → フォーカスされている「Attribute」名に、「latitude」と入力
 → 「Type」の選択肢から、「Double」を選択
・再々度、「+」をクリック
 → フォーカスされている「Attribute」名に、「longitude」と入力
 → 「Type」の選択肢から、「Double」を選択


15)「Event」エンティティに対応する「NSManagedObject subclass」を作成(P.26)
・「14」の状態で(「Event」エンティティが選択されたままで)、メニュー「File> New> New File...」を選択


・開いたダイアログの左カラムで、「iOS」の「Core Data」を選択し、右カラム「NSManagedObject subclass」を選択し、「Next」
・保存場所の指定。特にオプションなど指定せず、「Create」


・「Event.h」と「Event.m」が生成されます(中身も、勝手に入ります!)


16)「RootViewController.m」に「Event.h」をインポート(P.27)
▼「#import "RootViewController.h"」の直後に、下記コード追加
-------
#import "Event.h"
-------


17)「RootViewController.h」に「addEvent」メソッドを宣言(P.29)
▼「@end」の直前に、下記コード追加
-------
- (void)addEvent;
-------


18)「RootViewController.m」に「addEvent」メソッドを追加(P.29〜32)
▼「9」の直後に、下記コード追加
-------
- (void)addEvent {
CLLocation *location = [locationManager location]; //「locationManager」は、CLLocationManagerクラスのインスタンス
if (!location) {
return; }

//「Event」エンティティの新規インスタンスを作成
Event *event = (Event *)[NSEntityDescription insertNewObjectForEntityForName:@"Event" inManagedObjectContext:managedObjectContext];
//「cordinate」は、CLLocationクラスのプロパティ。英語では「座標」という意味を持つ
CLLocationCoordinate2D coordinate = [location coordinate];
//「event」インスタンスに値を設定
[event setLatitude:[NSNumber numberWithDouble:coordinate.latitude]];
[event setLongitude:[NSNumber numberWithDouble:coordinate.longitude]];
[event setCreationDate:[NSDate date]];
//
//▼参考)
//『CLLocation Class リファレンス』 http://developer.apple.com/library/ios/#DOCUMENTATION/CoreLocation/Reference/CLLocation_Class/CLLocation/CLLocation.html#//apple_ref/doc/uid/TP40007126
//『CLLocationManager Class リファレンス』 http://developer.apple.com/library/ios/#documentation/CoreLocation/Reference/CLLocationManager_Class/CLLocationManager/CLLocationManager.html

NSError *error = nil;
if (![managedObjectContext save:&error]) {
// エラーを処理する
}

//場所を指定(atIndex:)して、要素(event)を挿入
[eventsArray insertObject:event atIndex:0];

// RowとSectionが「0」のNSIndexPathを作って、indexPathインスタンスに代入する
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:0 inSection:0];


[self.tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
[self.tableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:0] atScrollPosition:UITableViewScrollPositionTop animated:YES];
//
//▼参考)
//『UITableViewにcellを動的に追加/削除する2つの方法。』 http://www.cocoalife.net/2010/04/post_543.html
// 『UITableViewをスクロールしたときに、一番下のセルがすべて出るよう吸着自動スクロールさせる方法』 http://ssdkfk.wordpress.com/2011/08/18/uitableviewをスクロールしたときに、一番下のセルがすべ/
//『iOS Table Viewプログラミングガイド(PDF)』 http://developer.apple.com/jp/devcenter/ios/library/documentation/TableView_iPhone.pdf
}
-------
※「Event *event = (Event *)[NSEntityDescription insertNewObjectForEntityForName:@"Event" inManagedObjectContext:managedObjectContext];」の「(Event *)」って、変わった使い方ですね。。リファレンスとかみても、よくわかりませんでした。 → http://d.hatena.ne.jp/jjj777/00000523/recID9437


19)「RootViewController.m」に「tableView:numberOfRowsInSection:」メソッドを追加(P.32)
▼「18」の直後に、下記コード追加
-------
// ロード時に呼び出され、セクションに含まれるセル数を返す
- (NSInteger)tableView:(UITableView *)tableView
numberOfRowsInSection:(NSInteger)section {
return [eventsArray count];
}
-------


20)「RootViewController.m」に「tableView:(UITableView *)tableView cellForRowAtIndexPath:」メソッドを追加(P.32)
▼「19」の直後に、下記コード追加
-------
// ロード時に呼び出され、セルの内容を返す
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath {

// タイムスタンプ用の日付フォーマッタ
static NSDateFormatter *dateFormatter = nil; if (dateFormatter == nil) {
dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setTimeStyle:NSDateFormatterMediumStyle];
[dateFormatter setDateStyle:NSDateFormatterMediumStyle];
}
// 緯度と経度用の数値フォーマッタ
static NSNumberFormatter *numberFormatter = nil; if (numberFormatter == nil) {
numberFormatter = [[NSNumberFormatter alloc] init];
[numberFormatter setNumberStyle:NSNumberFormatterDecimalStyle];
[numberFormatter setMaximumFractionDigits:3];
}
static NSString *CellIdentifier = @"Cell";

// 新規セルをデキューまたは作成する
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier] autorelease];
}
Event *event = (Event *)[eventsArray objectAtIndex:indexPath.row];
cell.textLabel.text = [dateFormatter stringFromDate:[event creationDate]];
NSString *string = [NSString stringWithFormat:@"%@, %@",
[numberFormatter stringFromNumber:[event latitude]],
[numberFormatter stringFromNumber:[event longitude]]]; cell.detailTextLabel.text = string;
return cell;
//
// ▼参考)
//『UITableViewCell Class Reference』 http://developer.apple.com/library/ios/#documentation/UIKit/Reference/UITableViewCell_Class/Reference/Reference.html
}
-------


21)テストビルド実行(P.33)
・「Run」をクリックすると、開発途中のアプリのビューが表示される。はずなのですが、再度エラーが発生しました。



・デバッガには「reason=The model used to open the store is incompatible with the one used to create the store」というメッセージが表示されています。どうやら、CoreDataが先ほど作成したsqliteと、整合性がとれなくなっているようです。
 → 参考)『iPhoneアプリ開発 備忘録:Core Data Navigation-Based 2月6日』 http://ameblo.jp/mattmatsui/entry-10452051631.html
・ぱん(Lion+Xcode4.2)の場合「/Users/(ユーザ名)/Library/Application Support/iPhone Simulator/5.0/Applications/xxxxxxxxxxxxxxxxxx/Documents」の中にある「Locations.sqlite」をターミナルから削除して、再度 iPhoneシミュレータを終了して、再度「Run」すると解決しました。
・下記コードを「RootViewController.m」の「- (void)viewDidLoad」の「}」の直前に挿入してビルド(Run)すると「+」ボタンでセルが追加されるようになります。あくまでテスト用コードなので、ビルドで内容を確認したら、コメントアウトします。
-------
//▼テストビルド(21)用コード
eventsArray = [[NSMutableArray alloc] init]; //テストが終わったら、この行はコメントアウトすること!
-------




22)「RootViewController.m」の「viewDidLoad」メソッドを編集(P.36〜37)
▼「8」の最後「}」の直前に、下記コード追加
-------
// sqliteへの「request」を準備(内容無し)
NSFetchRequest *request = [[NSFetchRequest alloc] init];

//「Event」エンティティの「managedObjectContext」を「entity」にセット
NSEntityDescription *entity = [NSEntityDescription entityForName:@"Event" inManagedObjectContext:managedObjectContext];

//「request」に「entity」を代入
[request setEntity:entity];

//「sortDescriptor」に、ソート順指定の情報を代入
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"creationDate" ascending:NO];

//「sortDescriptor」を、「sortDescriptors」に代入(変換)
NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor,nil];

//「request」に「ソート情報(sortDescriptors)」を代入
[request setSortDescriptors:sortDescriptors];

// 割り当て済みのオブ ジェクトを解放
[sortDescriptors release];
[sortDescriptor release];

//「request」を実行し、結果を可変コピーして、可変配列「mutableFetchResults」に代入
NSError *error = nil;
NSMutableArray *mutableFetchResults = [[managedObjectContext executeFetchRequest:request error:&error] mutableCopy];
if (mutableFetchResults == nil) {
// エラーを処理する
}

//View Controller(self)に、「mutableFetchResults」を設定
[self setEventsArray:mutableFetchResults];

// 割り当て済みオブジェクトを解放
[mutableFetchResults release];
[request release];

// ▼参考
//『NSFetchRequest Class Reference』 http://developer.apple.com/library/ios/#documentation/Cocoa/Reference/CoreDataFramework/Classes/NSFetchRequest_Class/NSFetchRequest.html
//・Core Dataのデータをフェッチするためのリクエストである。このオブジェクトを利用して、保存領域(persistent store)からデータを
// 読み出し、その結果をFetched results controllerに保存する
// →『Core Data 勉強日記 (4)』 http://blog.natsuapps.com/2010/02/core-data-4.html
//『NSSortDescriptor Class Reference』 http://developer.apple.com/library/ios/#documentation/Cocoa/Reference/Foundation/Classes/NSSortDescriptor_Class/Reference/Reference.html
//『オブジェクトを列挙してNSArrayを作りたい』 http://konton.ninpou.jp/program/cocoa/dataobject/nsarray.html#iwo
-------


23)「RootViewController.m」に「tableView:commitEditingStyle:forRowAtIndexPath:」メソッドを追加(P.39)
▼「20」の直後に、下記コード追加
-------
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle
forRowAtIndexPath:(NSIndexPath *)indexPath {
if (editingStyle == UITableViewCellEditingStyleDelete) {
// 指定のインデックスパスにある管理オブジェクトを削除する。
NSManagedObject *eventToDelete = [eventsArray objectAtIndex:indexPath.row];
[managedObjectContext deleteObject:eventToDelete];

// 配列とTable Viewを更新する。
[eventsArray removeObjectAtIndex:indexPath.row];
[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:YES];

// 変更をコミットする。
NSError *error = nil;
if (![managedObjectContext save:&error]) {
// エラーを処理する。
}
}
}
//『UITableViewDataSource Protocol Reference』 http://developer.apple.com/library/ios/#documentation/UIKit/Reference/UITableViewDataSource_Protocol/Reference/Reference.html#//apple_ref/occ/intfm/UITableViewDataSource/tableView:commitEditingStyle:forRowAtIndexPath:
// その他参考) http://ameblo.jp/xcc/entry-10468549510.html
-------


24)「Run」でビルドして、実行


以上で、終了です。

▼自分用TODO:CoreDataの参考資料として、下記も目を通す;
・『CoreData』 http://www.gamvaro.com/kswiki/index.php?OS関係%2FiPhone用OS(IOS)%2FCoreData
・『CoreDataの構成』 http://iphone-dev.g.hatena.ne.jp/hao_yayoi/



◆以下、ソース一覧 -----------------------------------


▼「LocationsAppDelegate.h」
-------
#import <UIKit/UIKit.h> //「<」「>」は半角で

// クラス宣言→ @interface クラス名:スーパークラス <デリゲート(指定した別のクラスにメッセージを丸投げできるよう設定する)>
@interface LocationsAppDelegate : UIResponder <UIApplicationDelegate> //「<」「>」は半角で

//『UIWindow 〜iPhoneアプリ開発の虎の巻〜』 http://iphone-tora.sakura.ne.jp/uiwindow.html
@property (strong, nonatomic) UIWindow *window;
@property (nonatomic, retain) UINavigationController *navigationController;

// 下記「▼参考」参照
@property (readonly, strong, nonatomic) NSManagedObjectContext *managedObjectContext;
@property (readonly, strong, nonatomic) NSManagedObjectModel *managedObjectModel;
@property (readonly, strong, nonatomic) NSPersistentStoreCoordinator *persistentStoreCoordinator;

- (void)saveContext;
- (NSURL *)applicationDocumentsDirectory;

@end

UINavigationController *navigationController;


// ▼参考
//『Core Data Overview : 重要なクラス』 http://blog.natsuapps.com/2010/09/core-data-overview_5352.html
//・「Managed Object Context」 http://cocoadevcentral.com/articles/000086.php#9
//・「Managed Object Model」 http://cocoadevcentral.com/articles/000086.php#3
//・「NSPersistentStoreCoordinator」http://cocoadevcentral.com/articles/000086.php#10
-------


▼「LocationsAppDelegate.m」
-------
#import "LocationsAppDelegate.h"
#import "RootViewController.h"


@implementation LocationsAppDelegate

@synthesize window = _window;
@synthesize navigationController;

@synthesize managedObjectContext = __managedObjectContext;
@synthesize managedObjectModel = __managedObjectModel;
@synthesize persistentStoreCoordinator = __persistentStoreCoordinator;


- (void)dealloc
{
[_window release];
[__managedObjectContext release];
[__managedObjectModel release];
[__persistentStoreCoordinator release];
[super dealloc];
}


- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
// チュートリアルでは削除されてるけど、ここの部分はXcode4.2の「Empty Application」テンプレートだと必須
self.window = [[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]] autorelease];

RootViewController *rootViewController = [[RootViewController alloc] initWithStyle:UITableViewStylePlain];
NSManagedObjectContext *context = [self managedObjectContext];
if (!context) {
// エラーを処理する
}
// 管理オブジェクトコンテキストをView Controllerに渡す
rootViewController.managedObjectContext = context;
UINavigationController *aNavigationController = [[UINavigationController alloc]
initWithRootViewController:rootViewController];
self.navigationController = aNavigationController;

//チュートリアルでは「window」だけど、「_window」に変更してます
[_window addSubview:[navigationController view]];
[_window makeKeyAndVisible];
[rootViewController release];
[aNavigationController release];
return YES;
}


- (void)applicationWillResignActive:(UIApplication *)application
{
/*
Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
*/
}

- (void)applicationDidEnterBackground:(UIApplication *)application
{
/*
Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
*/
}

- (void)applicationWillEnterForeground:(UIApplication *)application
{
/*
Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background.
*/
}

- (void)applicationDidBecomeActive:(UIApplication *)application
{
/*
Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
*/
}

- (void)applicationWillTerminate:(UIApplication *)application
{
// Saves changes in the application's managed object context before the application terminates.
[self saveContext];
}

- (void)saveContext
{
NSError *error = nil;
NSManagedObjectContext *managedObjectContext = self.managedObjectContext;
if (managedObjectContext != nil)
{
if ([managedObjectContext hasChanges] && ![managedObjectContext save:&error])
{
/*
Replace this implementation with code to handle the error appropriately.

abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
*/
NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
abort();
}
}
}

#pragma mark - Core Data stack

/**
Returns the managed object context for the application.
If the context doesn't already exist, it is created and bound to the persistent store coordinator for the application.
*/
- (NSManagedObjectContext *)managedObjectContext
{
if (__managedObjectContext != nil)
{
return __managedObjectContext;
}

NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
if (coordinator != nil)
{
__managedObjectContext = [[NSManagedObjectContext alloc] init];
[__managedObjectContext setPersistentStoreCoordinator:coordinator];
}
return __managedObjectContext;
}

/**
Returns the managed object model for the application.
If the model doesn't already exist, it is created from the application's model.
*/
- (NSManagedObjectModel *)managedObjectModel
{
if (__managedObjectModel != nil)
{
return __managedObjectModel;
}
NSURL *modelURL = [[NSBundle mainBundle] URLForResource:@"Locations" withExtension:@"momd"];
__managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
return __managedObjectModel;
}

/**
Returns the persistent store coordinator for the application.
If the coordinator doesn't already exist, it is created and the application's store added to it.
*/
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator
{
if (__persistentStoreCoordinator != nil)
{
return __persistentStoreCoordinator;
}

NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:@"Locations.sqlite"];

NSError *error = nil;
__persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];
if (![__persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:&error])
{
/*
Replace this implementation with code to handle the error appropriately.

abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.

Typical reasons for an error here include:
* The persistent store is not accessible;
* The schema for the persistent store is incompatible with current managed object model.
Check the error message to determine what the actual problem was.


If the persistent store is not accessible, there is typically something wrong with the file path. Often, a file URL is pointing into the application's resources directory instead of a writeable directory.

If you encounter schema incompatibility errors during development, you can reduce their frequency by:
* Simply deleting the existing store:
[[NSFileManager defaultManager] removeItemAtURL:storeURL error:nil]

* Performing automatic lightweight migration by passing the following dictionary as the options parameter:
[NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption, [NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption, nil];

Lightweight migration will only work for a limited set of schema changes; consult "Core Data Model Versioning and Data Migration Programming Guide" for details.

*/
NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
abort();
}

return __persistentStoreCoordinator;
}

#pragma mark - Application's Documents directory

/**
Returns the URL to the application's Documents directory.
*/
- (NSURL *)applicationDocumentsDirectory
{
return [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject];
}

@end
-------


▼「RootViewController.h」
-------
#import <CoreLocation/CoreLocation.h> //「<」「>」は半角で

// クラス宣言→ @interface クラス名:スーパークラス <デリゲート(指定した別のクラスにメッセージを丸投げできるよう設定する)>
@interface RootViewController : UITableViewController <CLLocationManagerDelegate> { //「<」「>」は半角で
// インスタンス変数の宣言
NSMutableArray *eventsArray; // イベント配列
NSManagedObjectContext *managedObjectContext; // 管理オブジェクトコンテキスト
CLLocationManager *locationManager; // Core Locationマネージャ
UIBarButtonItem *addButton; // 追加ボタン
}
// メソッドの宣言(ここでは、setter & getterを作るオマジナイを記述)
@property (nonatomic, retain) NSMutableArray *eventsArray;
@property (nonatomic, retain) NSManagedObjectContext *managedObjectContext;
@property (nonatomic, retain) CLLocationManager *locationManager;
@property (nonatomic, retain) UIBarButtonItem *addButton;

- (void)addEvent;

@end



// ▼参考
//『Objective-CでのDelegateとは』 http://konton.ninpou.jp/program/cocoa/delegate.html
//『@propertyでnonatomic指定していいの?』 http://ringsbell.blog117.fc2.com/blog-entry-350.html
//『Objective-Cの @property と @synthesize の組み合わせが何をやっているのかを解説』 http://d.hatena.ne.jp/nakamura001/20101101/1288632739

-------


▼「RootViewController.m」
-------
#import "RootViewController.h"
#import "Event.h"

@implementation RootViewController
// setter & getter を作るオマジナイを記述
@synthesize eventsArray;
@synthesize managedObjectContext;
@synthesize locationManager;
@synthesize addButton;
//
// ▼参考
//『Objective-Cの @property と @synthesize の組み合わせが何をやっているのかを解説』
// → http://d.hatena.ne.jp/nakamura001/20101101/1288632739


// インスタンスメソッド定義→ -(戻り値の型) メソッド名 : (引数の型) 引数名
- (CLLocationManager *)locationManager {
if (locationManager != nil) {
return locationManager;
}
locationManager = [[CLLocationManager alloc] init];
locationManager.desiredAccuracy = kCLLocationAccuracyNearestTenMeters;
locationManager.delegate = self;
return locationManager;
}
//
// ▼参考
//『メソッド呼びだし』 http://ja.wikipedia.org/wiki/Objective-C#.E3.83.A1.E3.82.BD.E3.83.83.E3.83.89.E5.91.BC.E3.81.B3.E3.81.A0.E3.81.97
//『メソッド定義とメッセージ式』 http://www.atmarkit.co.jp/fcoding/articles/objc/03/objc03b.html
//
//『CLLocationManager 〜iPhoneアプリ開発の虎の巻〜』 http://iphone-tora.sakura.ne.jp/cllocationmanager.html
//『<公式ガイド>位置情報対応プログラミングガイド』 http://developer.apple.com/jp/devcenter/ios/library/documentation/LocationAwarenessPG.pdf
//『GPSを利用する方法』 http://d.hatena.ne.jp/ntaku/20090228/1235816377


- (void)locationManager:(CLLocationManager *)manager
didUpdateToLocation:(CLLocation *)newLocation
fromLocation:(CLLocation *)oldLocation {
addButton.enabled = YES;
}
- (void)locationManager:(CLLocationManager *)manager
didFailWithError:(NSError *)error {
addButton.enabled = NO;
}
//
// ▼参考
//『CLLocationで現在位置を取得する』http://iphone-app-developer.seesaa.net/article/128902019.html



- (void)viewDidLoad {
[super viewDidLoad];
// タイトルを設定
self.title = @"Locations";
//「Edit」ボタンのセットアップ
self.navigationItem.leftBarButtonItem = self.editButtonItem;
//「+」ボタンのセットアップ(非活性ボタンにして配置)
addButton = [[UIBarButtonItem alloc]
initWithBarButtonSystemItem:UIBarButtonSystemItemAdd
target:self action:@selector(addEvent)];
addButton.enabled = NO;
self.navigationItem.rightBarButtonItem = addButton;
// ロケーションマネージャを起動する。
[[self locationManager] startUpdatingLocation];

//▼テストビルド(21)用コード
//eventsArray = [[NSMutableArray alloc] init];

// sqliteへの「request」を準備(内容無し)
NSFetchRequest *request = [[NSFetchRequest alloc] init];

//「Event」エンティティの「managedObjectContext」を「entity」にセット
NSEntityDescription *entity = [NSEntityDescription entityForName:@"Event" inManagedObjectContext:managedObjectContext];

//「request」に「entity」を代入
[request setEntity:entity];

//「sortDescriptor」に、ソート順指定の情報を代入
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"creationDate" ascending:NO];

//「sortDescriptor」を、「sortDescriptors」に代入(変換)
NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor,nil];

//「request」に「ソート情報(sortDescriptors)」を代入
[request setSortDescriptors:sortDescriptors];

// 割り当て済みのオブ ジェクトを解放
[sortDescriptors release];
[sortDescriptor release];

//「request」を実行し、結果を可変コピーして、可変配列「mutableFetchResults」に代入
NSError *error = nil;
NSMutableArray *mutableFetchResults = [[managedObjectContext executeFetchRequest:request error:&error] mutableCopy];
if (mutableFetchResults == nil) {
// エラーを処理する
}

//View Controller(self)に、「mutableFetchResults」を設定
[self setEventsArray:mutableFetchResults];

// 割り当て済みオブジェクトを解放
[mutableFetchResults release];
[request release];

// ▼参考
//『NSFetchRequest Class Reference』 http://developer.apple.com/library/ios/#documentation/Cocoa/Reference/CoreDataFramework/Classes/NSFetchRequest_Class/NSFetchRequest.html
//・Core Dataのデータをフェッチするためのリクエストである。このオブジェクトを利用して、保存領域(persistent store)からデータを
// 読み出し、その結果をFetched results controllerに保存する
// →『Core Data 勉強日記 (4)』 http://blog.natsuapps.com/2010/02/core-data-4.html
//『NSSortDescriptor Class Reference』 http://developer.apple.com/library/ios/#documentation/Cocoa/Reference/Foundation/Classes/NSSortDescriptor_Class/Reference/Reference.html
//『オブジェクトを列挙してNSArrayを作りたい』 http://konton.ninpou.jp/program/cocoa/dataobject/nsarray.html#iwo



}


- (void)viewDidUnload {
self.eventsArray = nil;
self.locationManager = nil;
self.addButton = nil;
}
- (void)dealloc {
[managedObjectContext release];
[eventsArray release];
[locationManager release];
[addButton release];
[super dealloc];
}
//
// ▼参考
//『UIViewController のメモリ管理まとめ』 http://hamasyou.com/blog/archives/000384
// → init で確保したメモリは dealloc で破棄する
// → viewDidload で確保したメモリは dealloc で破棄する。メモリ不足警告時には、didReceiveMemoryWarning メソッドから呼び出される、viewDidUnload で破棄する。


- (void)addEvent {
CLLocation *location = [locationManager location]; //「locationManager」は、CLLocationManagerクラスのインスタンス
if (!location) {
return; }

//「Event」エンティティの新規インスタンスを作成
Event *event = (Event *)[NSEntityDescription insertNewObjectForEntityForName:@"Event" inManagedObjectContext:managedObjectContext];
//「cordinate」は、CLLocationクラスのプロパティ。英語では「座標」という意味を持つ
CLLocationCoordinate2D coordinate = [location coordinate];
//「event」インスタンスに値を設定
[event setLatitude:[NSNumber numberWithDouble:coordinate.latitude]];
[event setLongitude:[NSNumber numberWithDouble:coordinate.longitude]];
[event setCreationDate:[NSDate date]];
//
//▼参考)
//『CLLocation Class リファレンス』 http://developer.apple.com/library/ios/#DOCUMENTATION/CoreLocation/Reference/CLLocation_Class/CLLocation/CLLocation.html#//apple_ref/doc/uid/TP40007126
//『CLLocationManager Class リファレンス』 http://developer.apple.com/library/ios/#documentation/CoreLocation/Reference/CLLocationManager_Class/CLLocationManager/CLLocationManager.html

NSError *error = nil;
if (![managedObjectContext save:&error]) {
// エラーを処理する
}

//場所を指定(atIndex:)して、要素(event)を挿入
[eventsArray insertObject:event atIndex:0];

// RowとSectionが「0」のNSIndexPathを作って、indexPathインスタンスに代入する
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:0 inSection:0];


[self.tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
[self.tableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:0] atScrollPosition:UITableViewScrollPositionTop animated:YES];
//
//▼参考)
//『UITableViewにcellを動的に追加/削除する2つの方法。』 http://www.cocoalife.net/2010/04/post_543.html // 『UITableViewをスクロールしたときに、一番下のセルがすべて出るよう吸着自動スクロールさせる方法』 http://ssdkfk.wordpress.com/2011/08/18/uitableviewをスクロールしたときに、一番下のセルがすべ/
//『iOS Table Viewプログラミングガイド(PDF)』 http://developer.apple.com/jp/devcenter/ios/library/documentation/TableView_iPhone.pdf


}


// ロード時に呼び出される。セクションに含まれるセル数を返す
- (NSInteger)tableView:(UITableView *)tableView
numberOfRowsInSection:(NSInteger)section {
return [eventsArray count];
}


// ロード時に呼び出され、セルの内容を返す
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath {

// タイムスタンプ用の日付フォーマッタ
static NSDateFormatter *dateFormatter = nil; if (dateFormatter == nil) {
dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setTimeStyle:NSDateFormatterMediumStyle];
[dateFormatter setDateStyle:NSDateFormatterMediumStyle];
}
// 緯度と経度用の数値フォーマッタ
static NSNumberFormatter *numberFormatter = nil; if (numberFormatter == nil) {
numberFormatter = [[NSNumberFormatter alloc] init];
[numberFormatter setNumberStyle:NSNumberFormatterDecimalStyle];
[numberFormatter setMaximumFractionDigits:3];
}
static NSString *CellIdentifier = @"Cell";

// 新規セルをデキューまたは作成する
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier] autorelease];
}
Event *event = (Event *)[eventsArray objectAtIndex:indexPath.row];
cell.textLabel.text = [dateFormatter stringFromDate:[event creationDate]];
NSString *string = [NSString stringWithFormat:@"%@, %@",
[numberFormatter stringFromNumber:[event latitude]],
[numberFormatter stringFromNumber:[event longitude]]]; cell.detailTextLabel.text = string;
return cell;
//
// ▼参考)
//『UITableViewCell Class Reference』 http://developer.apple.com/library/ios/#documentation/UIKit/Reference/UITableViewCell_Class/Reference/Reference.html
}


- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle
forRowAtIndexPath:(NSIndexPath *)indexPath {
if (editingStyle == UITableViewCellEditingStyleDelete) {
// 指定のインデックスパスにある管理オブジェクトを削除する。
NSManagedObject *eventToDelete = [eventsArray objectAtIndex:indexPath.row];
[managedObjectContext deleteObject:eventToDelete];

// 配列とTable Viewを更新する。
[eventsArray removeObjectAtIndex:indexPath.row];
[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:YES];

// 変更をコミットする。
NSError *error = nil;
if (![managedObjectContext save:&error]) {
// エラーを処理する。
}
}
}
//『UITableViewDataSource Protocol Reference』 http://developer.apple.com/library/ios/#documentation/UIKit/Reference/UITableViewDataSource_Protocol/Reference/Reference.html#//apple_ref/occ/intfm/UITableViewDataSource/tableView:commitEditingStyle:forRowAtIndexPath:
// その他参考) http://ameblo.jp/xcc/entry-10468549510.html

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}

- (void)didReceiveMemoryWarning
{
// Releases the view if it doesn't have a superview.
[super didReceiveMemoryWarning];

// Release any cached data, images, etc that aren't in use.
}

#pragma mark - View lifecycle

/*
// Implement loadView to create a view hierarchy programmatically, without using a nib.
- (void)loadView
{
}
*/

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
// Return YES for supported orientations
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}

@end
-------


▼「Event.h」
-------
#import <Foundation/Foundation.h> //「<」「>」は半角で
#import <CoreData/CoreData.h> //「<」「>」は半角で


@interface Event : NSManagedObject

@property (nonatomic, retain) NSDate * creationDate;
@property (nonatomic, retain) NSNumber * longitude;
@property (nonatomic, retain) NSNumber * latitude;

@end
-------


▼「Event.m」
-------
#import "Event.h"


@implementation Event

@dynamic creationDate;
@dynamic longitude;
@dynamic latitude;

@end
-------


・・・以上。なにかご意見や不具合などありましたら、コメント欄や、Twitter(@toaster4us)でご連絡ください。

Emacs で、C言語のコンパイル&実行環境をつくる

JUGEMテーマ:コンピュータ



Cのプログラムを、気軽にコンパイルして、結果をみられる環境を作りたい。と思いました。ちなみに使っているのは、MacBookAir + OS X Lion です。

※gcc をインストールするまでの課程で出会ったハードなハードルは、前回のエントリーを御覧ください。。


さて「環境を作りたい」とはいうものの、Emacsがきちんと動いていて、gccが使える環境なら、難しいことは何もありません。

下記の手順でOKなはずです;

1)コードを書いて、拡張子 .c で保存する
2) M-x compile を実行(M は、Mac の自分の環境では、コマンドキー)
3)プロンプトで、 make -k と出てくる。その部分を消去する
4)プロンプトで、 gcc ファイル名 を実行
5) a.out という実行ファイルが生成される
6) M-x shell と打って,shell-mode のバッファを起動
7)$ ./a.out を実行
→ 実行結果が表示される



でも、もっといい方法がないかなと思って、探してみました。記事末にある「参考サイト」をもとに設定した環境は、こちら;

A)「M-x compile」のショートカット(C-c c)を設定する
  ▼ ~/.emacs ファイルに、下記を追記;
---
;; C-c c で compile コマンドを呼び出す
(define-key mode-specific-map "c" 'compile)
---

B)「M-x shell」のショートカット(C-c C-z)を設定する
  ▼ ~/.emacs ファイルに、下記を追記;
---
;; C-c C-z で shell コマンドを呼び出す
(define-key mode-specific-map "¥C-z" 'shell-command)
---

C) shell-command 実行時に、補完が効くように設定する
  ▼ ~/.emacs ファイルに、下記を追記;
---
;; Thanks to "http://www.namazu.org/~tsuchiya/elisp/#shell-command-with-completion"
(load-file "~/.emacs.d/shell-command.el")
(shell-command-completion-mode)
---

  ▼ ~/.emacs.d/ の中に「shell-command.el」を入れる。ダウンロードは、下記サイトから可能。
---
http://www.namazu.org/~tsuchiya/elisp/#shell-command-with-completion
---



でも、Emacs 内のshell commandから実行すると、「scanf」を使ってキーボードからインプットを伴うプログラムの場合、勝手に値が入って結果が返されちゃう。使ってるバージョンは、「GNU Emacs 22.3.1 (i386-apple-darwin9.8.0, Carbon Version 1.6.0) of 2010-01-10 on gs674-seijiz.local」だけど。。 なんでだろう。。また今度調べてみるかなあ。いや、調べないだろうなあ。。結局、ターミナルでやっちゃうのかなあ。漢(おとこ)じゃないな、やっぱ俺。




参考サイト)
・「@ Emacs で C 言語プログラミングを始める人へのイントロダクション」
・「shell-command のコマンド入力に補完が効くようにする|私の .emacs で設定している項目」
・「Emacsのススメ」
・「EmacsからMacでC言語をコンパイルしてみる」


Mac OS X 10.7.2(Lion)に、macports で gcc を入れる(だけの)物語

JUGEMテーマ:コンピュータ


この物語は、OS 10.7.2 Lion で、ターミナルから gcc を使おうとしただけなのに、半日以上の時間を、その環境構築に費やした男の物語である。。(ひでーなぁ。。。)



まず、発端は。OS 10.7.2 Lion で、ターミナルから gcc を使おうとしたら、
「-bash: gcc: command not found」って言われたところから始まります。

---
$ ls -la /usr/bin | grep gcc
---
とかしても、何もひっかからない。

「Lion」にする前までは、問題なくできてたと思うんだけど。。。と思って、ググッた結果;
---
「Mac OS X Lion に gcc-4.2 をインストールするよ」
http://kin2ku.org/protein/wiki/tadanomemo/memos/2011/10/18/mac_lion_gcc
---
というエントリーを発見。

早速;
---
$ port search gcc
---
を実行して、gcc をmacportsで探しました。

---
apple-gcc42 @5664 (lang)
Apple's version of gcc 4.2
---
というのを発見しました。



でも「$ port search gcc」の直下に気になるアラートを発見;
「Warning: port definitions are more than two weeks old, consider using selfupdate」

負けるものか!と思って、
---
$ sudo port -d selfupdate
---
とかやってみるんだけど;

---
(前略)
checking Xcode version... 4.2
checking for gcc... /usr/bin/llvm-gcc-4.2
checking whether the C compiler works... no
configure: error: in `/opt/local/var/macports/sources/rsync.macports.org/release/base':
configure: error: C compiler cannot create executables
See `config.log' for more details
shell command "cd /opt/local/var/macports/sources/rsync.macports.org/release/base && CC=/usr/bin/llvm-gcc-4.2 ./configure --prefix=/opt/local --with-tclpackage=/Library/Tcl --with-install-user=root --with-install-group=admin --with-directory-mode=0755 --enable-readline && make && make install" returned error 77
DEBUG: Error installing new MacPorts base: shell command failed (see log for details)
while executing
"macports::selfupdate [array get global_options] base_updated"
Error: /opt/local/bin/port: port selfupdate failed: Error installing new MacPorts base: shell command failed (see log for details)
---
とかなってしまう。



またまたググッた結果;
---
「MacPorts で selfupdate が何とかと言われたときの解決方法」
http://weble.org/2011/01/05/macports-selfupdate
---

---
「古くなったMacPortsを再インストール」
http://www.1x1.jp/blog/2011/06/macports_reinstall.html
---
というのを発見

どうやら、macports を丸ごと入れ替えたほうがよさそうだ。
(&そしてそれは、面倒くさそうだ。。でも、Lionをやめるよりは、ハードル低そうだ。。)

◆◆

「$ port installed」とかして、何かバックアップとったほうがいいのあるかなあと見てみる;
---
$ port installed
The following ports are currently installed:
bash-completion @1.2_0 (active)
bzip2 @1.0.6_0 (active)
curl @7.21.2_2+ssl (active)
curl-ca-bundle @7.21.2_4 (active)
db46 @4.6.21_6 (active)
expat @2.0.1_1 (active)
gdbm @1.8.3_3 (active)
gettext @0.18.1.1_2 (active)
git-core @1.7.4_0+bash_completion+doc+python27 (active)
gperf @3.0.4_0 (active)
libffi @3.0.9_0 (active)
libiconv @1.13.1_0 (active)
libidn @1.19_0 (active)
libpcap @1.1.1_0 (active)
libyaml @0.1.3_0 (active)
mysql5 @5.1.53_0 (active)
mysql5-server @5.1.53_0 (active)
ncurses @5.7_1 (active)
ncursesw @5.7_1 (active)
ngrep @1.45_0 (active)
openssl @1.0.0b_0
openssl @1.0.0c_0 (active)
p5-error @0.17016_0 (active)
perl5 @5.8.9_0 (active)
perl5.8 @5.8.9_3 (active)
pkgconfig @0.25_2 (active)
popt @1.16_0 (active)
python27 @2.7.1_1 (active)
python_select @0.3_0 (active)
readline @6.1.002_0 (active)
rsync @3.0.7_1 (active)
ruby19 @1.9.2-p0_3+nosuffix (active)
sqlite3 @3.7.5_0 (active)
zlib @1.2.5_0 (active)
---

mysql は、macportsで入れてるんだった。。ひとまず、バックアップ取っておこう;



---
$ /opt/local/bin/mysqldump5 -u root -p --all-databases > ~/mysql.dump
---
※「/tmp」とかに保存すると、Macの場合、再起動するだけでファイルが消えてしまうから注意。どんだけ、temporary なんだよまったく!!!

※ほかにも、必要なファイルや設定がないか確認して。消す前に絶対保存しておきましょう!!


念のため;
---
$ port installed > ~/macports_installed.txt
---
で、インストールされてるportsを保存しておこう。



さて。ようやく、古い macports を消す段に。

---
$ sudo port deactivate active
---
を実行。。けど、エラー発生;



---
---> Deactivating bash-completion @1.2_0
---> Unable to uninstall/deactivate bash-completion @1.2_0, the following ports depend on it:
---> bash-completion @1.2_0
Error: Target org.macports.deactivate returned: Please uninstall the ports that depend on bash-completion first.
Log for bash-completion is at: /opt/local/var/macports/logs/_opt_local_var_macports_registry_portfiles_bash-completion_1.2_0/main.log
Warning: Failed to execute portfile from registry for bash-completion @1.2_0
---> Deactivating bash-completion @1.2_0
---> Unable to uninstall/deactivate bash-completion @1.2_0, the following ports depend on it:
---> bash-completion @1.2_0
Error: port deactivate failed: Please uninstall the ports that depend on bash-completion first.
---
「bash-completion」に依存するアプリを先に消せ。と言われてるみたい。

---
$ sudo port uninstall --follow-dependents bash-completion
---
とかしてみるけど
---
Warning: Failed to execute portfile from registry for bash-completion @1.2_0
too many nested evaluations (infinite loop?)
---
とか言われる。。

じゃあ、仕方ないから;
---
$ sudo port -f uninstall installed
---
を実行。なんかいろいろWarningが出るけど、処理自体は終了。

試しに;
---
$ sudo port deactivate active
---
と打つと
---
Error: No ports matched the given expression
---
と言われるので、無事アンインストールできた模様。

でも、
---
$ sudo port clean all
---
とすると
---
Error: Unable to open port: invalid command name "installs_libs"
---
とか言われる。無視を決め込むことにしよう。。。

続けて、各種設定を保存するため;
---
$ sudo mv /opt/local /opt/local.old
---
を実行

各種Tclファイルが保存されている(シンボリックリンクが貼られている)、下記ディレクトリを削除;
---
$ sudo rm -rf /Library/Tcl/macports1.0
---
と実行

以上で、古いmacportsとは縁を切りました。

◆◆

さて。

新しいmacportsをインストールしましょう。つい最近リリースされた、Lion対応をウリにした、macports 2.0.x をインストールします。

今回は、ソースからでなく、パッケージからにします。macportsのオフィシャルサイトでも、よっぽどの理由がない限り、パッケージからインストールしてください。と書いてます。素直に、従うことにします。



最新版「MacPorts-2.0.3」のパッケージを、オフィシャルサイトからダウンロードします。
そして、ダイアログに従って、インストール実行。。。

と、

またエラー発生。下記のようなアラートが表示されます;
---
MacPorts-2.0.3はこのコンピュータにインストールできません。
Xcode is not installed or was installed with UNIX Development(10.5+) or Command Line Support(10.4) deselected
---

いや、Xcode入れてるよ。iOSアプリつくろうとして、勉強してるもん。。なんだか、いじめられてる気分になってくる。けど、ここで逃げても、何も解決しない。。

Beta の時に 4.2 とか入れたのがまずかったのかな。。とか思って、Xcodeを入れなおすことにする。



Mac の App Store から、4.2.1 のパッケージををダウンロードしてインストールを実行。。。

でも、うまく動かない。。

そっか、たしかXcodeって、特別なアンインストールしないとだめだったのかも。;


---
$ sudo /Developer/Library/uninstall-developer-folder
---
とかやるんだけど
---
ERROR: Xcode appears to be running. You must first quit the following programs before the uninstaller can proceed:
4622 ?? S 0:06.84 /Developer/Applications/Xcode.app/Contents/MacOS/Xcode -psn_0_1716643
---
と返される。マシンを再起動して、再度;
---
$ sudo /Developer/Library/uninstall-developer-folder
---
と実行すると;
---
Start time: 2011年 12月20日 火曜日 11時34分07秒 JST
Analyzing devtools package: 'com.apple.pkg.ApplicationLoaderLeo'...
(中略)
Removing Xcode Caches...
find: /var/folders/lv/3j5swdns08z9vl080j61s8540000gn/C/com.apple.DeveloperTools: No such file or directory
Removing Xcode Documentation...
Removing empty devtools directories...
Finish time: 2011年 12月20日 火曜日 11時34分35秒 JST
---
と出る。たぶん、成功したのかな。

念のため;
---
$ sudo rm -r Developer/
---
を実行して、きれいさっぱり。気持ちを盛り上げる。




さて。

ふたたび、Mac App Store から、Xcodeをインストールしようとすると、
既にインストール済みと出る。

なんで?

どうやら「アプリケーション」フォルダにある
「Install Xcode.app」がインストール済みということらしい。わかりづれー。。



「アプリケーションフォルダー」内の「install Xcode.app」をダブルクリックし、
インストール開始。



今度は、無事インストール完了。

◆◆

いよいよ、gccのインストール。

---
「Mac OS X Lion に gcc-4.2 をインストールするよ」
http://kin2ku.org/protein/wiki/tadanomemo/memos/2011/10/18/mac_lion_gcc
---
に従って;

---
$ ls -la /usr/bin | grep gcc
---
を確認し;
---
$ sudo port install apple-gcc42
---
を実行。



---
---> Computing dependencies for apple-gcc42
---> Dependencies to be installed: gcc_select
---> Fetching archive for gcc_select
---> Attempting to fetch gcc_select-0.1_5.darwin_11.noarch.tbz2 from http://packages.macports.org/gcc_select
---> Fetching gcc_select
---> Verifying checksum(s) for gcc_select
---> Extracting gcc_select
---> Configuring gcc_select
---> Building gcc_select
---> Staging gcc_select into destroot
---> Installing gcc_select @0.1_5
---> Activating gcc_select @0.1_5
---> Cleaning gcc_select
---> Fetching archive for apple-gcc42
---> Attempting to fetch apple-gcc42-5666.3_2.darwin_11.x86_64.tbz2 from http://packages.macports.org/apple-gcc42
---> Fetching apple-gcc42
---> Attempting to fetch gcc-5666.3.tar.gz from http://distfiles.macports.org/apple-gcc42
---> Verifying checksum(s) for apple-gcc42
---> Extracting apple-gcc42
---> Applying patches to apple-gcc42
---> Configuring apple-gcc42
---> Building apple-gcc42
---> Staging apple-gcc42 into destroot
---> Installing apple-gcc42 @5666.3_2
---> Activating apple-gcc42 @5666.3_2
---> Cleaning apple-gcc42
---
入ったっぽい。でもしかし、macportsって、インストールの時間かかるよなあ。。いろいろ面倒くさいことを、裏っ側でやってくれているんだろうな。感謝。ありがとう☆



gccがインストールされているか確認;
---
$ gcc -dumpversion
---
と実行すると
---
4.2.1
---
と返ってくる。



念のため、パスとかも通ってるか。きちんと動作するか、確認;
---
「MacのターミナルでC言語の練習環境を用意してみたよ」
http://kawairi.jp/weblog/vita/201104062128
---
に従って、hello world スクリプトを作成し、コンパイル&実行する



---
$ cd c_practices/
$ ls
hello.c
$ gcc hello.c
$ ls
a.out hello.c
$ ./a.out
Hello World!
---

パチパチパチ。



っていうか、gcc の環境作るのに、半日使っちゃったよ。。いいのか、それで (TOT)

MySQLとかRubyとかの再インストールは、また今度やろうと思います。

【 Xcode4.2 】Interface Builder使わずに、座標を合わせたい(習作1)

IB(Interface Builder)を使わない場合、パーツを配置するための座標指定がちょっと面倒。

だったら、方眼の画像を背景に敷いて作業すればいいんじゃないの。と思ったわけです。


【 ▲クリックして拡大 】





例のごとく、Xcodeにて;

1)File > New > New Project... を選択
2)iOS の Application から「Empty Application」を選択肢「Next」ボタンを押す
3)Product Name を適当に(今回は「ImageTest」と)入力。「Use Core Data」などのチェックボックスは外して「Next」ボタンを押す
4)プロジェクトフォルダの保存場所を指定。「Create local git repository for this project」は、とりあえずチェックしたままでOK。

5)方眼画像(640_960.png)を、Xcodeの左ペインにドラッグしてコピー

6)Xcodeの左ペインから「AppDelegate.m」を選択して「- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:」の内容を、下記の通りに編集(→参考画像

-------------------------
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]] autorelease];
// Override point for customization after application launch.

UIImage *img = [UIImage imageNamed:@"640_960.png"];
UIImageView *bg_graph = [[UIImageView alloc] initWithImage:img];
[self.window addSubview:bg_graph];

UILabel* label = [[[UILabel alloc] initWithFrame:self.window.bounds] autorelease];
label.text = @"天地左右★センター";
label.textAlignment = UITextAlignmentCenter;
label.textColor = [UIColor blackColor];
label.backgroundColor = [UIColor clearColor];
[self.window addSubview:label];

UIButton *btn = [UIButton buttonWithType:UIButtonTypeRoundedRect];
btn.frame = CGRectMake(80, 260, 160, 100);
[btn setTitle:@"左80上260☆160×100" forState:UIControlStateNormal];
[self.window addSubview:btn];

[self.window makeKeyAndVisible];
return YES;
}
-------------------------

7)Xcodeの「Run」ボタンを押して実行。




今回使った方眼画像は、こちら(↓)
Interface Builder 無しでも、方眼背景で作業できる
【→オリジナルサイズを表示して、保存】


※ファイル名を「640_960.png」で保存

実は、方眼だけでなくて、定規みたいに目盛りがついてたらもっと便利なのかも。。

どうでしょう?

【 Xcode4.2 】複数のUIViewControllerを持つアプリを、 IB(Interface Builder)無しで作る

今回は、ボタンを押すと2つの「UIViewController」が切り替わる(前後する)アプリをつくってみました。

UIViewController1

UIViewController2


元ネタは、『iPhoneプログラミング UIKit 詳解リファレンス』のUnit3.1(「UIViewControllerと画面」)です。もちろん、IBを使わずに作成します。今回のエントリーについて理解を深めたい方は『UIKit 詳解リファレンス』を購入して読むことをお勧めします。※ただ、この本ちょっと古くて、Xcode4.2 から勉強はじめる人にはハードル高い部分があるので、このエントリーが手助けとなればと。



A)プロジェクトの準備

1)File > New > New Project... を選択
2)iOS の Application から「Empty Application」を選択肢「Next」ボタンを押す
3)Product Name を適当に(今回は「SVTest」と)入力。「Use Core Data」などのチェックボックスは外して「Next」ボタンを押す
4)プロジェクトフォルダの保存場所を指定。「Create local git repository for this project」は、とりあえずチェックして「Create」ボタンを押す
5)下記のように、最低限のファイルが生成された状態となります

001



B)「View1」用ファイルの生成

6)File > New > New FIle... を選択
7)iOS のApplication から「UIViewController subclass」を選択し「Next」ボタンを押す
8)Class 欄に「ViewController1」と入力。「Targeted for iPad」と「With XIB for interface」のチェックボックスは外して「Next」を押す
9)ファイルの保存場所の指定。GroupもTargetsも「MVTest」になっていることを確認して、「Create」ボタンを押す
10)下記のように「ViewController1.h」と「ViewController1.m」が作成されています。「8)」で「With XIB for interface」のチェックを外しているので、NIBファイル(.xibファイル)は作成されていません。

002



C)「View2」用ファイルの生成

11)File > New > New FIle... を選択
12)iOS のApplication から「UIViewController subclass」を選択し「Next」ボタンを押す
13)Class 欄に「ViewController2」と入力。「Targeted for iPad」と「With XIB for interface」のチェックボックスは外して「Next」を押す
14)ファイルの保存場所の指定。GroupもTargetsも「MVTest」になっていることを確認して、「Create」ボタンを押す
15)下記のように「ViewController2.h」と「ViewController2.m」が作成されています。「13)」で「With XIB for interface」のチェックを外しているので、NIBファイル(.xibファイル)は作成されていません。

003



D)「UIVirewController1.m」と「UIViewController2.m」のコーディング

i )「UIViewController1.m」を編集
 ①「- (id)initWithNibName:」部分を一括削除
 ② 今回メモリ管理は必要無いので見通しをよくするため「- (void)didReceiveMemoryWarning」部分を削除
 ③「- (void)viewDidLoad { }」部分のコメントアウトを外す
 ④「Hello, world」ラベル、及び背景描画のコードを「③」内に追加
--------------------
UILabel* label = [[[UILabel alloc] initWithFrame:self.view.bounds] autorelease];
label.text = @"Hello, world";
label.textAlignment = UITextAlignmentCenter;
label.backgroundColor = [UIColor whiteColor];
label.textColor = [UIColor blackColor];
label.autoresizingMask= UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;

[self.view addSubview:label];
--------------------

 ⑤「画面遷移」ボタン描画のコードを「④」の直後に追加
--------------------
UIButton* button = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[button setTitle:@"画面遷移" forState:UIControlStateNormal];
[button sizeToFit];
CGPoint newPoint = self.view.center;
newPoint.y += 50;
button.center = newPoint;
button.autoresizingMask = UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleBottomMargin;
[button addTarget:self action:@selector(buttonDidPush) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:button];
--------------------

 ⑥「画面遷移」ボタンメソッドのコードを、「- (void)viewDidLoad { }」の直後(⑤のコード下にある「 } 」直後)に追加
--------------------
-(void)buttonDidPush {
[self.view.window sendSubviewToBack:self.view];
}
--------------------


ii )「UIViewController2.m」を編集
 ⑦「- (id)initWithNibName:」部分を一括削除
 ⑧ 今回メモリ管理は必要無いので見通しをよくするため「- (void)didReceiveMemoryWarning」部分を削除
 ⑨「- (void)viewDidLoad{ }」部分のコメントアウトを外す
 ⑩「こんばんわ、世界!」ラベル、及び背景描画のコードを「⑨」内に追加
--------------------
UILabel* label = [[[UILabel alloc] initWithFrame:self.view.bounds] autorelease];
label.text = @"こんばんわ、世界!";
label.textAlignment = UITextAlignmentCenter;
label.backgroundColor = [UIColor blackColor];
label.textColor = [UIColor whiteColor];
label.autoresizingMask= UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;

[self.view addSubview:label];
--------------------

 ⑪「画面遷移」ボタン描画のコードを「⑩」の直後に追加
--------------------
UIButton* button = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[button setTitle:@"画面遷移" forState:UIControlStateNormal];
[button sizeToFit];
CGPoint newPoint = self.view.center;
newPoint.y += 50;
button.center = newPoint;
button.autoresizingMask = UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleBottomMargin;
[button addTarget:self action:@selector(buttonDidPush) forControlEvents:UIControlEventTouchUpInside];

[self.view addSubview:button];
--------------------
 
 ⑫「画面遷移」ボタンメソッドのコードを、「- (void)viewDidLoad{ }」の直後(⑪のコード下にある「 } 」直後)に追加
--------------------
-(void)buttonDidPush {
[self.view.window sendSubviewToBack:self.view];
}
--------------------



E)「AppDelegate.h」と「AppDelegate.m」のコーディング

i )「AppDelegate.h」を編集
 ⑬ 「@interface AppDelegate : UIResponder <UIApplicationDelegate>(※「<」「>」は半角)」と「@end」の間にある「@property (strong, nonatomic) UIWindow *window;」をコメントアウトして、インスタンス変数を宣言するための下記コード追加
--------------------
{
UIWindow* _window;
UIViewController* _viewController1;
UIViewController* _viewController2;
}
--------------------

ii )「AppDelegate.m」を編集
 ⑭ ViewController1と2をインポートするために「#import "AppDelegate.h"」直後に下記コード追加
--------------------
#import "ViewController1.h"
#import "ViewController2.h"
--------------------

 ⑮ 「- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { } 」内の「self.window.backgroundColor = [UIColor whiteColor];」をコメントアウト
 ⑯ ViewController1と2のインスタンスを作成し、_window にaddSubviewして、1を前面に出すためのコードを、「⑮」の直後に追加
--------------------
_viewController1 = [[ViewController1 alloc] init];
_viewController2 = [[ViewController2 alloc] init];

[_window addSubview:_viewController1.view];
[_window addSubview:_viewController2.view];

[_window bringSubviewToFront:_viewController1.view];
--------------------

 ⑰「⑯」直後の「 [self.window makeKeyAndVisible];」を「 [_window makeKeyAndVisible];」に変更
 ⑱ インスタンス変数が参照しているインスタンスを解放するために、「- (void)dealloc { }」内を下記に変更
--------------------
[_viewController1 release];
[_viewController2 release];
[_window release];
[super dealloc];
--------------------


以上です。「Run」ボタンを押すと、アプリが起動します。



今回編集した4つのファイルは、以下のとおりです。


▼「ViewController1.m」
------------------------------------
#import "ViewController1.h"

@implementation ViewController1


// - (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil // ① 関係ないので削除
// - (void)didReceiveMemoryWarning // ② 今回は見通しよくするために削除

#pragma mark - View lifecycle

/*
// Implement loadView to create a view hierarchy programmatically, without using a nib.
- (void)loadView
{
}
*/


// ③ コメントアウトを外す
// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void)viewDidLoad
{
[super viewDidLoad];

// ④「Hello, world」ラベル、及び背景描画
UILabel* label = [[[UILabel alloc] initWithFrame:self.view.bounds] autorelease];
label.text = @"Hello, world";
label.textAlignment = UITextAlignmentCenter;
label.backgroundColor = [UIColor whiteColor];
label.textColor = [UIColor blackColor];
label.autoresizingMask= UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;

[self.view addSubview:label];

// ⑤「画面遷移」ボタン描画
UIButton* button = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[button setTitle:@"画面遷移" forState:UIControlStateNormal];
[button sizeToFit];
CGPoint newPoint = self.view.center;
newPoint.y += 50;
button.center = newPoint;
button.autoresizingMask = UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleBottomMargin;
[button addTarget:self action:@selector(buttonDidPush) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:button];

}

// ⑥ 「画面遷移」ボタンメソッド
-(void)buttonDidPush {
[self.view.window sendSubviewToBack:self.view];
}

- (void)viewDidUnload
{
[super viewDidUnload];
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
// Return YES for supported orientations
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}

@end
------------------------------------


▼「ViewController2.m」
------------------------------------
#import "ViewController2.h"

@implementation ViewController2

// - (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil // ⑦ 関係ないので削除
// - (void)didReceiveMemoryWarning // ⑧ 今回は見通しよくするために削除

#pragma mark - View lifecycle

/*
// Implement loadView to create a view hierarchy programmatically, without using a nib.
- (void)loadView
{
}
*/


// ⑨ コメントアウトを外す。
// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void)viewDidLoad
{
[super viewDidLoad];

// ⑩「こんばんわ、世界!」ラベル、及び背景描画
UILabel* label = [[[UILabel alloc] initWithFrame:self.view.bounds] autorelease];
label.text = @"こんばんわ、世界!";
label.textAlignment = UITextAlignmentCenter;
label.backgroundColor = [UIColor blackColor];
label.textColor = [UIColor whiteColor];
label.autoresizingMask= UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;

[self.view addSubview:label];

// ⑪「画面遷移」ボタン描画
UIButton* button = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[button setTitle:@"画面遷移" forState:UIControlStateNormal];
[button sizeToFit];
CGPoint newPoint = self.view.center;
newPoint.y += 50;
button.center = newPoint;
button.autoresizingMask = UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleBottomMargin;
[button addTarget:self action:@selector(buttonDidPush) forControlEvents:UIControlEventTouchUpInside];

[self.view addSubview:button];

}

// ⑫ 「画面遷移」ボタンメソッド
-(void)buttonDidPush {
[self.view.window sendSubviewToBack:self.view];
}


- (void)viewDidUnload
{
[super viewDidUnload];
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
// Return YES for supported orientations
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}

@end
------------------------------------


▼「AppDelegate.h」
------------------------------------
#import

@interface AppDelegate : UIResponder
// ⑬ プロパティのコメントアウトと、インスタンス変数の宣言
// @property (strong, nonatomic) UIWindow *window;

{
UIWindow* _window;
UIViewController* _viewController1;
UIViewController* _viewController2;
}


@end
------------------------------------


▼「AppDelegate.m」
------------------------------------
#import "AppDelegate.h"

//⑭ ViewController のインポート
#import "ViewController1.h"
#import "ViewController2.h"


@implementation AppDelegate

@synthesize window = _window;

- (void)dealloc
{
// ⑱ インスタンス変数が参照しているインスタンスの解放
[_viewController1 release];
[_viewController2 release];
[_window release];
[super dealloc];
}

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]] autorelease];
// Override point for customization after application launch.
// self.window.backgroundColor = [UIColor whiteColor]; // ⑮ コメントアウト

// ⑯ ViewController1と2のインスタンスを作成し、_window にaddSubviewして、1を前面に出す
_viewController1 = [[ViewController1 alloc] init];
_viewController2 = [[ViewController2 alloc] init];

[_window addSubview:_viewController1.view];
[_window addSubview:_viewController2.view];

[_window bringSubviewToFront:_viewController1.view];

// ⑰ 「window」を「_window」に変更
[_window makeKeyAndVisible];
return YES;
}

- (void)applicationWillResignActive:(UIApplication *)application
{
/*
Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
*/
}

- (void)applicationDidEnterBackground:(UIApplication *)application
{
/*
Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
*/
}

- (void)applicationWillEnterForeground:(UIApplication *)application
{
/*
Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background.
*/
}

- (void)applicationDidBecomeActive:(UIApplication *)application
{
/*
Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
*/
}

- (void)applicationWillTerminate:(UIApplication *)application
{
/*
Called when the application is about to terminate.
Save data if appropriate.
See also applicationDidEnterBackground:.
*/
}

@end
------------------------------------



▼参考書



【 Xcode4.2 】 IB(Interface Builder)を使わず、複数viewのアプリを作る

今回は、ボタンを押すとアラートが出るアプリ(単画面)を、つくってみました。

複数view画面+ア<br />
ラート表示


iPhoneプログラミングUIKit詳解リファレンス
』のUnit2.3(UIViewの入れ子構造)を元ネタに、Xcode4.2でIBを使わずにViewの入れ子も実現しています。

複数view画面


詳細な解説は『iPhoneプログラミングUIKit詳解リファレンス』を読むと理解が深まるかと思います。



A)プロジェクトの準備

1)File > New > New Project... を選択
2)iOS の Application から「Empty Application」を選択肢「Next」ボタンを押す
3)Product Name を適当に(今回は「SVTest」と)入力。「Use Core Data」などのチェックボックスは外して「Next」ボタンを押す
4)プロジェクトフォルダの保存場所を指定。「Create local git repository for this project」は、とりあえずチェックして「Create」ボタンを押す
5)下記のように、最低限のファイルが生成された状態となります

Xcode4.2 Empty Project の生成ファイル



B)コーディング

編集するファイルは、SVTest直下の「AppDelegate.h」と「AppDelegate.m」の2ファイルのみです。

i )「AppDelegate.h」を編集
 ① 「@property (strong, nonatomic) UIWindow *window;」をコメントアウト
 ② コメントアウトした①の直下に「{ UIWindow *_window ;}」を、記述

ii )「AppDelegate.m」を編集
 ③~⑦今回不要な「- (void)applicationWillResignActive:」~「- (void)applicationWillTerminate:」の記述(最後にある「@end」の直前まで)を削除して見通しをよくする
 ⑧「- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{ }」内の「self.window.backgroundColor = [UIColor whiteColor];」の直下に、「1-1」ボタンを描画するためのコード追加;
------------
UIButton* button11 = [UIButton buttonWithType:UIButtonTypeRoundedRect];
button11.frame = CGRectMake(10, 10, 300, 300);
[button11 setTitle:@"1-1" forState:UIControlStateNormal];
[button11 addTarget:self action:@selector(button11DidPush:)
forControlEvents:UIControlEventTouchUpInside];
[self.window addSubview:button11];
------------

iii )「AppDelegate.h」を編集
 ⑨「②」で追加したコード直下に「- (void)button11DidPush:(id)sender;」とコード追加(1-1ボタンメソッドの宣言)

iv )「AppDelegate.m」を編集
 ⑩「- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{ }」の最後の「}」の直下に1-1ボタンメソッドのコード追加
------------
- (void)button11DidPush:(id)sender {
[self alertMessage:sender];
}
------------

v )「AppDelegate.h」を編集
 ⑪「⑨」の直下に「- (void)alertMessage:(UIButton*)button;」とコード追加(アラート表示メソッドの宣言)

vi )「AppDelegate.m」を編集
 ⑫「⑩」の直下にアラート表示メソッドのコード追加
------------
- (void)alertMessage:(UIButton*)button {
NSString* title = [NSString stringWithFormat:@"self = %@", button.titleLabel.text];
NSString* superViewName;
if ([button.superview isKindOfClass:[UIButton class]] ){
superViewName = ((UIButton*)button.superview).titleLabel.text;
} else {
superViewName = @"UIViewController";
}
NSMutableString* subviews = [[[NSMutableString alloc] initWithCapacity:64] autorelease];
[subviews setString:@""];
for ( id view in button.subviews ) {
NSString* addString;
if ( [view isKindOfClass:[UIButton class]] ) {
addString = ((UIButton*)view).titleLabel.text;
} else if ( [view isKindOfClass:[UILabel class]]) {
addString = ((UILabel*)view).text;
} else {
addString = [view description];
}
if ( [subviews length] > 0) { //「>」は要半角置換
[subviews appendString:@", "];
}
[subviews appendString:addString];
}
NSString* message = [NSString stringWithFormat:@"superview = %@¥r¥nsubviews= %@", superViewName, subviews];
UIAlertView* alert = [[[UIAlertView alloc] initWithTitle:title message:message delegate:nil cancelButtonTitle:nil otherButtonTitles:@"OK", nil ] autorelease];
[alert show];

}
------------

vii )「AppDelegate.h」を編集
 ⑬4つ(「1-1-1」「1-1-2」「1-1-2-1」「1-1-2-2」)のボタンメソッドメソッドを宣言
------------
- (void)button111DidPush:(id)sender;
- (void)button112DidPush:(id)sender;
- (void)button1121DidPush:(id)sender;
- (void)button1122DidPush:(id)sender;
------------

viii )「AppDelegate.m」を編集
⑭「⑧」の直下に、4つ(「1-1-1」「1-1-2」「1-1-2-1」「1-1-2-2」)のボタンを描画するためのコード追加;
------------
UIButton* button111 = [UIButton buttonWithType:UIButtonTypeRoundedRect];
button111.frame = CGRectMake(20, 20, 260, 100);
[button111 setTitle:@"1-1-1" forState:UIControlStateNormal];
[button111 addTarget:self action:@selector(button111DidPush:)
forControlEvents:UIControlEventTouchUpInside];
[button11 addSubview:button111];

UIButton* button112 = [UIButton buttonWithType:UIButtonTypeRoundedRect];
button112.frame = CGRectMake(20, 180, 260, 100);
[button112 setTitle:@"1-1-2" forState:UIControlStateNormal];
[button112 addTarget:self action:@selector(button112DidPush:) forControlEvents:UIControlEventTouchUpInside];
[button11 addSubview:button112];

UIButton* button1121 = [UIButton buttonWithType:UIButtonTypeRoundedRect];
button1121.frame = CGRectMake(10, 10, 95, 80);
[button1121 setTitle:@"1-1-2-1" forState:UIControlStateNormal];
[button1121 addTarget:self action:@selector(button1121DidPush:) forControlEvents:UIControlEventTouchUpInside];
[button112 addSubview:button1121];

UIButton* button1122 = [UIButton buttonWithType:UIButtonTypeRoundedRect];
button1122.frame = CGRectMake(155, 10, 95, 80);
[button1122 setTitle:@"1-1-2-2" forState:UIControlStateNormal];
[button1122 addTarget:self action:@selector(button1122DidPush:) forControlEvents:UIControlEventTouchUpInside];
[button112 addSubview:button1122];
------------

⑮「⑩」の直下に、4つ(「1-1-1」「1-1-2」「1-1-2-1」「1-1-2-2」)のボタンメソッドのコード追加
------------
- (void)button111DidPush:(id)sender {
[self alertMessage:sender];
}
- (void)button112DidPush:(id)sender {
[self alertMessage:sender];
}
- (void)button1121DidPush:(id)sender {
[self alertMessage:sender];
}
- (void)button1122DidPush:(id)sender {
[self alertMessage:sender];
}
------------

以上です。「Run」ボタンを押すと、アラート表示するボタンのアプリが起動します。




完成した2つのファイルは、以下のとおりです。

▼「AppDelegate.h」
------------------------------------

#import <UIKit/UIKit.h> //「<」「>」は要半角置換

@interface AppDelegate : UIResponder <UIApplicationDelegate> //「<」「>」は要半角置換

// @property (strong, nonatomic) UIWindow *window; //① コメントアウト

{ UIWindow *_window ;} //② 追加

- (void)button11DidPush:(id)sender; // ⑨ ボタンメソッドの宣言
- (void)alertMessage:(UIButton*)button; //⑪ アラート表示メソッドの宣言

// ⑬ ボタンメソッドを追加して宣言・START
- (void)button111DidPush:(id)sender;
- (void)button112DidPush:(id)sender;
- (void)button1121DidPush:(id)sender;
- (void)button1122DidPush:(id)sender;
// ⑬ END

@end

------------------------------------

▼「AppDelegate.m」
------------------------------------

#import "AppDelegate.h"

@implementation AppDelegate

@synthesize window = _window;

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

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]] autorelease];
// Override point for customization after application launch.
self.window.backgroundColor = [UIColor whiteColor];
// ⑧ ボタンを描画・START
UIButton* button11 = [UIButton buttonWithType:UIButtonTypeRoundedRect];
button11.frame = CGRectMake(10, 10, 300, 300);
[button11 setTitle:@"1-1" forState:UIControlStateNormal];
[button11 addTarget:self action:@selector(button11DidPush:)
forControlEvents:UIControlEventTouchUpInside];
[self.window addSubview:button11];
// ⑧ END

// ⑭ ボタンを追加して描写・START
UIButton* button111 = [UIButton buttonWithType:UIButtonTypeRoundedRect];
button111.frame = CGRectMake(20, 20, 260, 100);
[button111 setTitle:@"1-1-1" forState:UIControlStateNormal];
[button111 addTarget:self action:@selector(button111DidPush:)
forControlEvents:UIControlEventTouchUpInside];
[button11 addSubview:button111];

UIButton* button112 = [UIButton buttonWithType:UIButtonTypeRoundedRect];
button112.frame = CGRectMake(20, 180, 260, 100);
[button112 setTitle:@"1-1-2" forState:UIControlStateNormal];
[button112 addTarget:self action:@selector(button112DidPush:) forControlEvents:UIControlEventTouchUpInside];
[button11 addSubview:button112];

UIButton* button1121 = [UIButton buttonWithType:UIButtonTypeRoundedRect];
button1121.frame = CGRectMake(10, 10, 95, 80);
[button1121 setTitle:@"1-1-2-1" forState:UIControlStateNormal];
[button1121 addTarget:self action:@selector(button1121DidPush:) forControlEvents:UIControlEventTouchUpInside];
[button112 addSubview:button1121];

UIButton* button1122 = [UIButton buttonWithType:UIButtonTypeRoundedRect];
button1122.frame = CGRectMake(155, 10, 95, 80);
[button1122 setTitle:@"1-1-2-2" forState:UIControlStateNormal];
[button1122 addTarget:self action:@selector(button1122DidPush:) forControlEvents:UIControlEventTouchUpInside];
[button112 addSubview:button1122];
// ⑭ END

[self.window makeKeyAndVisible];
return YES;

}

// ⑩ ボタンメソッド・START
- (void)button11DidPush:(id)sender {
[self alertMessage:sender];
}
// ⑩ END

// ⑮ ボタンメソッドを追加・START
- (void)button111DidPush:(id)sender {
[self alertMessage:sender];
}
- (void)button112DidPush:(id)sender {
[self alertMessage:sender];
}
- (void)button1121DidPush:(id)sender {
[self alertMessage:sender];
}
- (void)button1122DidPush:(id)sender {
[self alertMessage:sender];
}
// ⑮ END


// ⑫ アラート表示メソッド・START
- (void)alertMessage:(UIButton*)button {
NSString* title = [NSString stringWithFormat:@"self = %@", button.titleLabel.text];
NSString* superViewName;
if ([button.superview isKindOfClass:[UIButton class]] ){
superViewName = ((UIButton*)button.superview).titleLabel.text;
} else {
superViewName = @"UIViewController";
}
NSMutableString* subviews = [[[NSMutableString alloc] initWithCapacity:64] autorelease];
[subviews setString:@""];
for ( id view in button.subviews ) {
NSString* addString;
if ( [view isKindOfClass:[UIButton class]] ) {
addString = ((UIButton*)view).titleLabel.text;
} else if ( [view isKindOfClass:[UILabel class]]) {
addString = ((UILabel*)view).text;
} else {
addString = [view description];
}
if ( [subviews length] > 0) { //「>」は要半角置換
[subviews appendString:@", "];
}
[subviews appendString:addString];
}
NSString* message = [NSString stringWithFormat:@"superview = %@¥r¥nsubviews= %@", superViewName, subviews];
UIAlertView* alert = [[[UIAlertView alloc] initWithTitle:title message:message delegate:nil cancelButtonTitle:nil otherButtonTitles:@"OK", nil ] autorelease];
[alert show];

}
// ⑫ END



// ③ 削除 - (void)applicationWillResignActive:(UIApplication *)application
// ④ 削除 - (void)applicationDidEnterBackground:(UIApplication *)application
// ⑤ 削除 - (void)applicationWillEnterForeground:(UIApplication *)application
// ⑥ 削除 - (void)applicationDidBecomeActive:(UIApplication *)application
// ⑦ 削除 - (void)applicationWillTerminate:(UIApplication *)application


@end


------------------------------------




▼参考書




Xcode4.2で「Hello,World」の次に作るサンプルアプリ(翻訳)

この記事は、Xcode4.2のチュートリアルの中で、ぱんが「イケている」と思った
The jungle, part 1: Basic UI Elementshttp://cupsofcocoa.com/2011/09/24/the-jungle-part-1/)」の作業内容を、日本語でメモしたものです。あくまでぱん自身の作業ログとしてのメモなので、かなりざっくりメモしてます。特に、Interface Builderでの作業は、画像付きでないとわかりづらいかと。。。そんなときは、「The jungle, part 1: Basic UI
Elements
」を参照しながら読んでください。





【今回の環境】
Xcode 4.2 on Mac OS X 10.7 Lion





▼<新規プロジェクトの作成> 1)Xcode 起動
2)起動画面の左にある「Create a new Xcode project」を選択
3)左カラム「iOS」の下にある「Application」を選択すると表示される、右カラムの中の「Empty Application」をダブルクリック
4)「Product Name」に「SDK Demo」と入力。その他オプションは選択せず「Next」をクリック
5)保存画面が表示されるので「Create」ボタンをクリック


▼<ファイル内容の確認>
「SDK Demo」フォルダの直下に作成されたファイルは;
 ・AppDelegate.h
 ・AppDelegate.m
 の2ファイルに加え、
 ・「Supporting Files」ディレクトリの中に;
  ・SDK Demo-info.plist
  ・InfoPlist.strings
  ・main.m
  ・SDK Demo-Prefix.pch
  の4ファイルが生成されている

 ※「SDK Demo」と同じ階層に;
  「Frameworks」
  「Products」
  という2つのフォルダもあるけれど、ひとまず無視


▼<Root View Controller を作成する>

 ※ RootViewControllerは、プロジェクトのファイル群の中で必須ではない。
 root view controller を作成せずに、delegateファイルの中にコードをまとめることもできる。
 でも、そうすると複雑なアプリだと見通しが悪くなる可能性があるので注意が必要

1)Xcodeのメニューから、File > New > New File... を選択
2)左カラム「iOS」の下にある「Cocoa Touch」を選択すると表示される、右カラムの中の「UIViewController subclass」を選択して「Next」をクリック
3)「Class」欄に「RootViewController」と記入する。「Subclass」は「UIVewController」となっていることを確認し、その下のオプション「With XIB for user interface」にチェックが付いていることを確認し「Next」をクリック
4)保存画面が表示されるので「Create」ボタンをクリック


▼<AppDelegate.h の編集>
------------------------------------------------------------------------------------------
#import <UIKit/UIKit.h>
@class RootViewController; //←コード追加
@interface AppDelegate : UIResponder <UIApplicationDelegate>

@property (nonatomic, retain) UIWindow *window;
@property (nonatomic, retain) RootViewController *rootViewController; //←コード追加
@end
------------------------------------------------------------------------------------------


▼<AppDelegate.m の編集>
------------------------------------------------------------------------------------------
#import "AppDelegate.h"
#import "RootViewController.h" //←コード追加

@implementation AppDelegate


@synthesize window = _window;
@synthesize rootViewController = _rootViewController; //←コード追加

- (void)dealloc
{
[_window release];
[_rootViewController release]; //←コード追加
[super dealloc];
}

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]] autorelease];
// Override point for customization after application launch.
self.window.backgroundColor = [UIColor whiteColor];
_rootViewController = [[RootViewController alloc] init]; //←コード追加
self.window.rootViewController = self.rootViewController; //←コード追加
[self.window makeKeyAndVisible];
return YES;
}

/*
この間のコードを削除し、見通し良くする
*/

@end
------------------------------------------------------------------------------------------
※「application:DidFinishLaunchingWithOptions:」は、アプリが起動するたびに、スクリーンと同じサイズのウインドウを生成するし、autoreleaseする。その行と、次のbackgroundを白に指定する行は、テンプレートが自動生成している。
※ その次の2行が、ここで大事な点だ。「RootViewController」インスタンスを初期化し、windowのrootViewControllerのpropertyとして設定している。ちなみに、iOS4.0になるまではview controllerを直接セットできなかったので、「 [_window addSubview:self.rootViewController.view]; 」と、別途viewを設定する必要があった。
※その次の2行で、実際にwindowを表示し、YESを返している。ちなみに、NOを返すと、アプリは終了する。


▼<「AppDelegate」ってなんなのか>

・すべてのプロジェクトについて、生成されるクラスで。iOSとアプリを繋ぐインターフェイス。
・アプリのローディングが済んだら「application:didFinishLaunchingWithOptions:」が呼ばれる。
・AppDelegateは、アプリ終了時/ステータスを保存する前/バックグラウンドになる前・復帰する際 などにも呼ばれる。 ちなみバックグラウンド(background)は、iOS4.0以降の特定機種で可能なマルチタスク環境におけるステータスです。 注意事項は、あんまり長いプロセスをここに記載しないこと。ハングアップしたように見えてしまうから。
・「Supporting Files」フォルダ内の main.m ファイル内に記載されている「UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]))」にある4番目の引数で、Delegate Classは指定されている。


▼<RootViewController.h の編集>
------------------------------------------------------------------------------------------
#import <UIKit/UIKit.h>

@interface RootViewController : UIViewController
{ int buttonPressCount; } //←コード追加

@property (nonatomic, retain) IBOutlet UILabel *buttonPressLabel; //←コード追加
@property (nonatomic, retain) IBOutlet UILabel *echoLabel; //←コード追加

- (IBAction)simpleButtonPressed:(id)sender; //←コード追加
- (IBAction)textFieldTextDidChange:(id)sender; //←コード追加

@end
------------------------------------------------------------------------------------------
※「IBOutlet」と「IBAction」は、コードに直接影響を与えない。Interface Builder が作用するためのコード上の目印となっているだけである。
※「IBAction」メソッドは、汎用(id)型の引数「sender」オブジェクトを持っていて、イベントのトリガーとなっている。引数は必須じゃないけど、トリガーを明示するためにあった方が便利。複数のオブジェクトを、1つのアクションメソッドでフックアップしたり、senderの複数のプロパティーにアクセスすることも可能。


▼<画面をセットする>
1)「RootViewController.xib」を選択
2)Xcodeウインドウ右上の「Utitities」ボタン(「View」と書かれた3ボタンの一番右)をクリック
3)「Utilities」の6つの切り替えスイッチの左から4番目(Show the Attributes Inspectoer)をクリック
4)「View(「1」のViewでなく、「Simulated Metrics」と並列の「View」)」の「Background」をプルダウンして「Group Table View Background Color」を選択
5)「Show the Object Library」ボタン(「Utilities」カラムの右下の方にある4ボタンの、左から3番目)をクリック
6)「Round Rect Button」と書かれた角丸ボタンを、中央カラムのiPhone画面にドラッグ&ドロップ。
7)ボタンをドラッグして、横160pxに伸ばす
8)ボタンの中央をダブルクリックし、文字入力モードにし「Press Me!」と入力
9)「6」と同じように、「Label」と書かれたパーツを「Press Me!」ボタン下にドラッグ&ドロップ
10)Labelをドラッグし、横128pxに伸ばす
11)「4」と同じようにプロパティを設定します。
 ・「Alignment」をセンターに
 ・「Text Color」を「Black」に
 ・「Shadow」を「White」に
 ・「Shadow Offset」を、「Horizoral:0」/「Vertical:1(デフォルトは「-1」)に
 ・「Text」から「Label」という文字列を削除
12)「6」と同じように、「Text Field」と書かれたパーツを中央あたりにドラッグ&ドロップ
13)「Text Field」をドラッグし、横160pxに伸ばす
14)「9」の「Label」を、「13」の「Text Field」下にコピーする。Optionキーを押しながら、ドラッグ&ドロップすればOK


▼<コネクションを貼る>
1)中央カラムのiPhoneウインドウの左「Placeholders」の下にある「File's Owner」をクリック
2)「Utilities」の6つの切り替えスイッチの一番右端(Show the Connections Inspector)をクリックし「Outlets」の1番目(buttonPressLabel)の右端の◯を「Press Me!」下のLabelにドラッグ&ドロップ
3)「2」の「buttonPressLabel」の下にある「echoLabel」の右端の◯を「Text Field」下のLabelにドラッグ&ドロップ
4)「2」の「Outlets」と並列の「Received Actions」の一番目(simpleButtonPressed)の右端の◯を「Press Me!」ボタンにドラッグ&ドロップし、出てきたプルダウンから「Touch Up Inside」を選択
5)「4」と同じく「Received Actions」より、2番目(textFieldTextDidChange)の右端の◯を「Text Field」にドラッグ&ドロップyし、出てきたプルダウンから「Editing Changed」を選択


▼<RootViewController.m を、以下の内容に書き換える>
------------------------------------------------------------------------------------------
#import "RootViewController.h"

@implementation RootViewController
@synthesize buttonPressLabel = _buttonPressLabel;
@synthesize echoLabel = _echoLabel;

#pragma mark - Memory Management
- (void)dealloc {
[_buttonPressLabel release];
[_echoLabel release];
}

#pragma mark - View lifecycle
- (void)viewDidLoad {
buttonPressCount = 0;
}

- (void)viewDidUnload {
[super viewDidUnload];
// Release any retained subviews of the main view to relieve memory usage
self.buttonPressLabel = nil;
self.echoLabel = nil;
}

#pragma mark - Action Methods
- (IBAction)simpleButtonPressed:(id)sender {
buttonPressCount++;
NSString *pluralHandlerString = (buttonPressCount == 1) ? @"time" : @"times";
NSString *displayString = [[NSString alloc] initWithFormat:@"Button pressed %d %@", buttonPressCount, pluralHandlerString];
self.buttonPressLabel.text = displayString;
[displayString release];
}

- (IBAction)textFieldTextDidChange:(id)sender {
UITextField *textField = (UITextField *)sender;
NSString *textFieldText = textField.text;
self.echoLabel.text = textFieldText;
}
@end
------------------------------------------------------------------------------------------


▼▼▼<最後にちょっと微調整(One More Thing)>
※文字入力が終わったら(改行ボタンを押したら)、キーボードを下にしまうように設定


▼<RootViewController.h の編集>
------------------------------------------------------------------------------------------
#import <UIKit/UIKit.h>

@interface RootViewController : UIViewController
{ int buttonPressCount; }

@property (nonatomic, retain) IBOutlet UILabel *buttonPressLabel;
@property (nonatomic, retain) IBOutlet UILabel *echoLabel;

- (IBAction)simpleButtonPressed:(id)sender;
- (IBAction)textFieldTextDidChange:(id)sender;
- (IBAction)dismissKeyboard:(id)senderr; //←コード追加

@end
------------------------------------------------------------------------------------------


▼<RootViewController.m の修正>
※最終行「@end」の前の行に、以下の3行を追加
------------------------------------------------------------------------------------------
- (IBAction)dismissKeyboard:(id)sender {
[(UITextField *)sender resignFirstResponder];
}
------------------------------------------------------------------------------------------


▼<コネクションを貼る(追加)>
1)中央カラムのiPhoneウインドウの左「Placeholders」の下にある「File's Owner」をクリック
2)「Utilities」の6つの切り替えスイッチの一番右端(Show the Connections Inspector)をクリックし「Received Actions」の一番目(dissmissKeyboard)の右端の◯を「Text Field」ボタンにドラッグ&ドロップし、出てきたプルダウンから「Did End On Exit」を選択





【アプリケーションの実行】
→ Xcode ウインドウ左上の「Run」ボタン(再生ボタン)をクリック
 ※Runボタン/Stopボタンの横にあるSchemeで、実行環境を選択(通常は「iPhone 5.0 Simulator」でOK)



以上


Xcode 4.2 で iOSの勉強はじめました

iPhone/iPad アプリ制作の勉強を、本格化しています。でも今、微妙なタイミングですね。何が微妙かというと「Xcode4.2」や「iOS5」のリリースに連動して、開発環境が激変しているからです。特に開発環境の変化は、初心者プログラマにとって、(特に非英語圏のプログラマにとって)非常に大きなハードルとなります。なにせ、日本語で適切なリファレンスがないんだから。。まあ、英語を読めばいいんだけど。でも、ちょっとハードルだと感じる人は多いよなあ。自分も含めて。

ここ最近勉強してきて、何点か非常にわかりづらいのは、以下の点です;

1)Xcodeテンプレートの自動生成ファイル群の変更
2)Storyboard導入
3)Automatic Reference Counting(ARC)導入


「1」〜「3」のどれもが、現在(2011/10末)出版されている(ほぼ)すべてのiOS関連の書籍の内容と、異なっているから、ど初心者が本のまんま何かコードを書いて勉強する。ということが不可能となっています。

いろいろ試行錯誤した結果、ぱんの学習方法は、以下のとおりとすることにしました。

・Interface Builder(IB)を使わないようにする(必要に応じて使うけど、最終的には外す)
・Storyboarを使わないようにする
・ARCを使わないようにする

って「全部使わないだけかよ」と言われそうだけど。うん。その通りです。でも、使わずに勉強するのも、初心者には大変なんだよなあ。

まず、「2」「3」 については、プロジェクトを作成する際、チェックボックスを外すことで、無視できます。

「1」については、テンプレートの構成内容が、今後も変わり続けることが予想されるので、本質的に理解してしまおうと思います。つまり、Interface Builder(IB)を使わなくてもコーディングできるようなるということです。

「1」について勉強していたら、おそらく「2」「3」の日本語情報も、充実してくるんではないかなあ。。。



なお「1」の理解のために参考にした(している)のは、以下のサイト(英語)です
「The Jungle, Part 1: Basic UI Elements」
http://cupsofcocoa.com/2011/09/24/the-jungle-part-1/

上の話で「IB」を使わないようにする。と書いてますが、まずは参考サイトのように、IB使ったソースを書いてみて、その後、IBの要素を削除していくことにします。このあたりは、随時学習メモをこのブログにアップできたらいいなあ。。



なお、ここまでの方針をたてるまでに参考にした書籍/サイトは、以下のものとなります;



→この本は、iOS SDKとしての「Xcodeの基本的な使い方」及び「Objective-CをどうやってXcodeで実行すればよいか」について、多くのヒントを与えてくれます。プログラム経験者には、次のステップへの道しるべとしてかなり役に立つ内容だと思います。※ 未経験者には「C言語」や、(オブジェクト指向言語を理解するきっかけとしての)「Ruby」などの初心者本をまずひと通り勉強することをお勧めします。





→売り切れないうちに買っておきましょう。古い本なので、現状と則さない内容も多いですが、UI KITの考え方や、IBを使わない開発についてのヒントがたくさん記載されています。ていうか、この本のiOS5対応版を出して欲しいです。。いま書いている途中だと願いたいです。



サイト「applications are expected to have a root view controller at the end of application launch」
http://www.mumuen.com/2011/09/applications-are-expected-to-have-root.html

※このサイトに出会ったのは、いろんな書籍のサンプルコードをXcode4.2で試していたら、上記サイト記事名
と同じエラーメッセージに出会って、Google先生に導いてもらったからです。




<追記:2011/11/01>

▼ちょっと古いけど、勉強になりそうなブログ
・「Interface Builderを使わずに作るiPhoneアプリケーション作成入門」
http://blog.asial.co.jp/502
・「IBを使わずに作るiPhoneアプリ作成入門:第2回」
http://blog.asial.co.jp/531
・「IBを使わずに作るiPhoneアプリ作成入門:第3回」
http://blog.asial.co.jp/539


本が出てます☆

主に、デザイン以外の
パートを担当してますw



発注者のためのWeb制作本。
制作者/開発者の方も必見!
Twitter
selected entries
categories
archives
recent comment
  • 【 Xcode4.2 】Interface Builder使わずに、座標を合わせたい(習作1)
    ぱん (12/21)
  • 【 Xcode4.2 】Interface Builder使わずに、座標を合わせたい(習作1)
    kuronobee (12/02)
  • 【随時更新】RailsGuide 訳『Rails 国際化対応 - I18n API』
    5.5 (12/07)
  • さくらインターネットで、gem install すると「chown/chgrp: Operation not permitted 」と叱られる件の対応
    はせがわ (11/03)
  • Rails 2.3 環境で、search_do(hyperestraier)と will_paginate を使って、全文検索を実現しようとした件
    ぱん (01/26)
  • UQ WiMAX を試してみる@多摩川・丸子橋近辺
    ぱん (10/26)
  • さくらインターネット・スタンダードプランのMySQLはインスタンスが1つまでだけど
    管理人 (09/19)
  • さくらインターネット・スタンダードプランのMySQLはインスタンスが1つまでだけど
    通りすがり (09/15)
  • HTMLコーディングの専門制作会社
    ぱん (07/23)
  • HTMLコーディングの専門制作会社
    とし (07/20)
recommend
去年ルノアールで
去年ルノアールで (JUGEMレビュー »)
せきしろ
■ルノアールで妄想が爆発
recommend
iPhoneプログラミングUIKit詳解リファレンス
iPhoneプログラミングUIKit詳解リファレンス (JUGEMレビュー »)
所 友太
内容古いですが、iOSプログラマー中級以上の階段を登るために、必要な本だと思います。iOS5対応版出ないかな。。
recommend
iOSプログラミング入門 - Objective-C + Xcode 4で学ぶ、iOSアプリ開発の基礎
iOSプログラミング入門 - Objective-C + Xcode 4で学ぶ、iOSアプリ開発の基礎 (JUGEMレビュー »)
大津 真
Ch.1「iOS プログラミングを始めるための基礎知識」でXcodeの概要を理解して、Ch.2「Objective-C の基礎知識」で、Objective-Cの考え方を理解できます。iOSプログラミングのキックオフにぴったり。
recommend
Agile Web Development With Rails (Pragmatic Programmers)
Agile Web Development With Rails (Pragmatic Programmers) (JUGEMレビュー »)
Sam Ruby,Dave Thomas,David Heinemeier Hansson
Railsの定番解説本が、Rails3に対応。英語版だけど、Rails経験者なら、なんとか読みこなせるかも。
links
profile
search this site.
others
mobile
qrcode
powered
無料ブログ作成サービス JUGEM
sponsored links