スポンサーサイト

  • 2015.09.25 Friday

一定期間更新がないため広告を表示しています

  • -
  • -
  • -
  • スポンサードリンク

【iOS開発メモ No.001 】『キーボードをしまう/閉じる』

  • 2012.03.21 Wednesday
  • 21:02
JUGEMテーマ:コンピュータ


テキストボックスに何か入力してもらった後、キーボードをしまう(閉じる)動作を実現したいと思いました。こんな(↓)感じです。









キーボードをしまう場合、よくあるのは;

1)リターンキーを押すと、入力が確定してキーボードが閉じる
2)「閉じる」ボタンがキーボードの上についていて、それをクリックすると閉じる
3)キーボードの領域以外の部分をクリックすると、キーボードが閉じる

というパターンでしょう。(ほかにもっとクールな方法があれば、知りたいです)

「1」と「2」は、トリガーとアクションがイメージしやすいので、ある程度プログラムの勘がある人なら、ググったりして実装方法を見つけるは難しくないんではないでしょうか。

「3」については、自分が何かアプリ使ってて、経験則的にやることあるけど。実装するとなると、そのイメージがすごく難しいです。少なくとも、ぱんには難しいです。

「キーボード以外の領域」というけれど、その中にもテキストボックスがあったり、ボタンがあったり、テキストラベルがあったり。それらを除外した領域の座標を、いちいち計算して、実現しないとだめなんだろうか。どうなんだろうか。。

と思っていたら、意外にもカンタンに実現できるをこと知りました。



まず、キー入力が発生する ViewController の Xib ファイルを開き、メインのViewインスタンスを選択し、IdentityInspector でクラスを「UIControl」に設定します。




次にXibに対応する、 .h ファイルを「Option + クリック」で Xib と .h を横に(アシスタントモードで)並べます。



次に、Xib の中で一番大元の View を選択します(ブルーラインで選択された状態になってる部分)。そして「Control + ドラッグ」で、 .h ファイルのメソッド指定部分に放り込む。 すると、下記のような状態になるので、Connection を「Action」に、Name を適当に「backgroundTapped」などに、Event を「Touch Up Inside」に指定し「Connect」ボタンをクリックします。





こんな感じで、.h にメソッドが宣言されます。



.m ファイルでは;



[self view] に対して、endEditing:YES を送って、編集モードを終わらせます。


以上です。


なあんだ。一番大元の View をタップしたら、編集モードを終わらせればいいだけか。


こういうのって、知ってしまった後になれば、カンタンすぎることなんだけど。知るまでの道のりが、意外に遠い。

こういうネタを集めて、体系的に整理して、非プログラマー向けの本書きたいなあ。すごく売れそうなタイトルも、考え済みです。どなたか編集者の方で、この記事読んでいらっしゃる方いたら、facebook等で、ぜひご連絡を!w



今日のネタ元は下記書籍です;

iOSプログラミング 第2版』。



【追記:2012年3月27日】
iOSプログラミング 第2版』は、一見小難しいですが、読破すれば力になること確実。『iOS開発におけるパターンによるオートマティズム』の内容で、かつ、それぞれの説明を素人でもわかりやすくした感じです。本気で学習したい人には、ぴったりの教材だと思います。ただし『iOSプログラミング 第2版』は、海外では2012年4月に、第三版(英語)が発売されます。英語ができる人は、それを待つのが賢明です。英語苦手な人は、『iOSプログラミング 第2版』と、第三版(英語)の両方買って、勉強するのがいい気がします。

【オススメ】Xcode4 チートシート(cheat sheet)

  • 2012.03.08 Thursday
  • 03:20
JUGEMテーマ:コンピュータ


Xcode4。使い込みだすと、ショートカットを覚える必要性を痛感します。

特に、MacBook Air などの表示領域が狭い環境だと、ウインドウ内の構成をこちょこちょ変えながら作業しないと、ストレスたまってしまいます。よね。

で、いいのないかなーと。ずーっと探してたんだけど。ようやく見つけました!

ぱんも最近すごくお世話になっている、『iOSプログラミング 第2版』の原書を出している「Big Nerd Ranch」という会社が、メルマガ登録するとダウンロードさせてくれる「Xcode 4 Quick Reference Card」がソレです。

ざっくりイメージは(↓)こんな感じ。



シンプル、かつ、必要十分の内容。ビジュアル重視で、わかりやすい。





ダウンロードするには(↓)赤丸部分をクリックして、メルマガ登録すればOK。






ちなみに、先にも書いたんですが、『iOSプログラミング 第2版』。相当いいです。




iOSプログラミング初心者を脱出したい人は、読んで損はないと思います。ぱんはまだ半分くらいしか読み進めていないのですが、読み終わったらレビュー書くつもりです。

【追記:2012年3月27日】
iOSプログラミング 第2版』は、一見小難しいですが、読破すれば力になること確実。『iOS開発におけるパターンによるオートマティズム』の内容で、かつ、それぞれの説明を素人でもわかりやすくした感じです。本気で学習したい人には、ぴったりの教材だと思います。ただし『iOSプログラミング 第2版』は、海外では2012年4月に、第三版(英語)が発売されます。英語ができる人は、それを待つのが賢明です。英語苦手な人は、『iOSプログラミング 第2版』と、第三版(英語)の両方買って、勉強するのがいい気がします。

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

  • 2011.12.29 Thursday
  • 00:17
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)でご連絡ください。

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

  • 2011.12.21 Wednesday
  • 18:44
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)

  • 2011.11.20 Sunday
  • 00:34
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)無しで作る

  • 2011.11.11 Friday
  • 04:09
今回は、ボタンを押すと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のアプリを作る

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

複数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」の次に作るサンプルアプリ(翻訳)

  • 2011.11.01 Tuesday
  • 19:58
この記事は、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の勉強はじめました

  • 2011.10.31 Monday
  • 21:14
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

【追記:2012年3月21日】
いま買うなら、上記の本でなく、断然『iOSプログラミング 第2版』がいいと思います。一見小難しいですが、読破すれば力になること確実。『iOS開発におけるパターンによるオートマティズム』の内容で、かつ、それぞれの説明を素人でもわかりやすくした感じです。本気で学習したい人には、ぴったりの教材だと思います。ただし『iOSプログラミング 第2版』は、海外では2012年4月に、第三版(英語)が発売されます。英語ができる人は、それを待つのが賢明です。(英語苦手な人は、『iOSプログラミング 第2版』と、第三版(英語)の両方買って、勉強するのがいい気がします。

iPhone + Objective-C はじめました

  • 2010.03.03 Wednesday
  • 20:47
Dave Mark,Jeff LaMarche
ソフトバンククリエイティブ
(2009-12-17)

一月程前、iPhone 買ったんですが。いや、楽しいですね。iPod Touch持っていたので、どうなんかなあと思ってたんですが。いつでも(Softbank 3G が入ればですが...)YouTubeやTwitterができたり、ゲームを落として遊んだり。スピーカー付いてるから、ちょっと友達に映像みせたり音楽きかせたりするのにも便利だし。手放せなくなりました。(いままでちょっと小馬鹿にしていてすみませんでした。。。)

でやっぱり、こんなかわいい端末を自分好みにしない手はないな。と思って。つまり、アプリつくらないテはないな。と思って。iPhone アプリ開発の勉強をはじめました。『はじめてのiPhone3プログラミング』という本が評判いいみたいなので、まずはこれを一通りやることにしました。Rails界でいうところの『RailsによるアジャイルWebアプリケーション開発』的な雰囲気で、一通りの開発ポイントを抑えることができそうです。

でも、実はObjective-Cって、知らないし。『はじめてのiPhone3プログラミング』には、Objective-Cを知ってるって前提で話すすめられちゃうし。どっかで根本的にObjective-Cというものを理解しないとなあと思って。本屋もいろいろ探したんだけど。いまのところ一番わかりやすい解説は、Webの中にありました。Ruby勉強し始めたころもそうだったけど、プログラムのど素人向け読み物は、Webで探した方がいいような気がします。そういうの読みつつ、初心者用チュートリアル本で何か実際に作りつつ学び、わかんないとこでてきたらリファレンス系の本で補って。「こんなことするにはどうしたらいいんだろう」って思ったら、レシピ系の本で探す。みたいな。

で、Webで見つけた、ど素人向け読み物。すごくObjective-Cの概要をつかむのに便利です。素敵です。ありがとうございました。以下、リンクです;

Objective-C入門その1:まずはコメントの書き方から

Objective-C入門その2:山の高さを知ろう!

Objective-C入門その3:「@」って何だ?

Objective-C入門番外編:オブジェクト指向って何だろう?

Objective-C入門その4:クラス宣言をマスターする

Objective-C入門その5:インスタンス変数宣言をマスターする

Objective-C入門その6:メソッドの宣言と実装をマスターする

Objective-C入門その7:アクセサメソッドをマスターする

Objective-C入門その8:メソッドの中身をマスターする

Objective-C入門その9:HelloWorldAppDelegate解決編(前編)

Objective-C入門その10:HelloWorldAppDelegate解決編(後編)

Objective-C入門その11:MyViewController.h一気読み

Objective-C入門その12:MyViewController.m一気読み

Objective-C入門その13:main.m一気読み 【追記:2012年3月21日】 いま買うなら、上記の本でなく、断然『iOSプログラミング 第2版』がいいと思います。一見小難しいですが、読破すれば力になること確実。『iOS開発におけるパターンによるオートマティズム』の内容で、かつ、それぞれの説明を素人でもわかりやすくした感じです。本気で学習したい人には、ぴったりの教材だと思います。ただし『iOSプログラミング 第2版』は、海外では2012年4月に、第三版(英語)が発売されます。英語ができる人は、それを待つのが賢明です。(英語苦手な人は、『iOSプログラミング 第2版』と、第三版(英語)の両方買って、勉強するのがいい気がします。

PR

calendar

S M T W T F S
      1
2345678
9101112131415
16171819202122
23242526272829
3031     
<< July 2017 >>

本が出てます☆

Twitter

selected entries

categories

archives

recent comment

  • Mac OS X Lion で、emacs を楽に使うために、Meta キーを「option」に設定したい。
    通りすがり (01/19)
  • 携帯キャリアの、アクセス制限(未成年保護)についてのまとめ
    たけのこの里 (10/01)
  • Mac OS X Lion で、emacs を楽に使うために、Meta キーを「option」に設定したい。
    イシカワ (07/16)
  • さくらインターネットで、gem install すると「chown/chgrp: Operation not permitted 」と叱られる件の対応
    sean (04/20)
  • さくらインターネットで、gem install すると「chown/chgrp: Operation not permitted 」と叱られる件の対応
    てっちー (03/24)
  • Mac OS X Lion で、emacs を楽に使うために、Meta キーを「option」に設定したい。
    JO (01/04)
  • Passbook(パスブック)on iOS6 (NDAに触れない範囲で...)
    ぱん (09/28)
  • Passbook(パスブック)on iOS6 (NDAに触れない範囲で...)
    宮腰睦美 (09/23)
  • magit を、Lion の emacs にインストール
    ぱん (05/08)
  • 【 Xcode4.2 】Interface Builder使わずに、座標を合わせたい(習作1)
    ぱん (12/21)

recommend

iOSプログラミング 第2版
iOSプログラミング 第2版 (JUGEMレビュー »)
アーロン・ヒレガス,ジョー・コンウェイ,Aaron Hillegass,Joe Conway
■独学で初心者を脱出するには、必読ではないでしょうか。翻訳でニュアンスが伝わらない部分があるので、原書と、サポートサイト(英語)を活用すべし!です。

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

去年ルノアールで
去年ルノアールで (JUGEMレビュー »)
せきしろ
■ルノアールで妄想が爆発

recommend

RailsによるアジャイルWebアプリケーション開発 第4版
RailsによるアジャイルWebアプリケーション開発 第4版 (JUGEMレビュー »)
Sam Ruby,Dave Thomas,David Heinemeier Hansson
■Railsのバイブル第4版の日本語版が2011年末にリリース!サーバサイドで準備するAPIや、Webサイト関連のもろもろは、やっぱRailsでしょう。

links

profile

search this site.

others

mobile

qrcode

powered by

無料ブログ作成サービス JUGEM