UINavigationControllerのpushViewControllerで画面遷移していく場合、 上部のナビゲーションバーのボタン追加はコーディングでしかやはりできないですよね?
1ページ毎にUINavigationBarをつける画面遷移方法もあるけど、それだと今度はUINavigationControllerの意味が・・・ですよね。
さて、ボタンの種類はUIBarButtonItem.hに定義されています。
typedef enum {
UIBarButtonSystemItemDone,
UIBarButtonSystemItemCancel,
UIBarButtonSystemItemEdit,
UIBarButtonSystemItemSave,
UIBarButtonSystemItemAdd,
UIBarButtonSystemItemFlexibleSpace,
UIBarButtonSystemItemFixedSpace,
UIBarButtonSystemItemCompose,
UIBarButtonSystemItemReply,
UIBarButtonSystemItemAction,
UIBarButtonSystemItemOrganize,
UIBarButtonSystemItemBookmarks,
UIBarButtonSystemItemSearch,
UIBarButtonSystemItemRefresh,
UIBarButtonSystemItemStop,
UIBarButtonSystemItemCamera,
UIBarButtonSystemItemTrash,
UIBarButtonSystemItemPlay,
UIBarButtonSystemItemPause,
UIBarButtonSystemItemRewind,
UIBarButtonSystemItemFastForward,
#if __IPHONE_3_0 <= __IPHONE_OS_VERSION_MAX_ALLOWED
UIBarButtonSystemItemUndo,
UIBarButtonSystemItemRedo,
#endif
#if __IPHONE_4_0 <= __IPHONE_OS_VERSION_MAX_ALLOWED
UIBarButtonSystemItemPageCurl,
#endif
} UIBarButtonSystemItem;
これを見る限りUndo、RedoボタンがiOS4から使えなくなってるようです。
ボタン追加はUIBarButtonItem initWithBarButtonSystemItem:で設定します。
UIBarButtonItem *addButton = [[UIBarButtonItem alloc]
initWithBarButtonSystemItem:UIBarButtonSystemItemSave
target:self
action:@selector(アクション後のメソッド名)];
NSLogではCoreDataのSQLは見る事ができないが、
com.apple.CoreData.SQLDebug
で出力できるらしい。
Google Developer Japan 2010に参加しようと思ったら、Quizに正解しないと参加できないとか!
しかも、プログラム提出とか開発者じゃないと答えられない問題w DevQuiz Google Developer Japan 2010 Quiz トップ
これ国家試験の情報処理より全然ムズかったり。 これ一度間違えたらダメなのかな?
休日なのに、選択問題のOAuthのプログラム作ってますw 成功したらLabsの方に載せておきます。
CoreDataの基礎 その1|CoreDataの基礎 その2|CoreDataの基礎 その3|CoreDataの基礎 その4
データ保存の一番肝なのはアプリケーション問わず
データモデル設計
昨今、Webアプリもネイティブアプリもプログラミングする時にSQLを書く事が皆無になりました(^^) 今は亡きAppleのWebObjectsにEOModlerってモデル管理ツールがありましたが、幸いXcodeにもこれと同等の管理ツールが付属しています。
便利!とは言え、やはりDBの知識は重要だとは思いますけど。
・TigerのCocoaにみるMVCの完成 - スマートなデータモデルを実現するCore Data ・CoreData - リレーションシップ(1) シンプルなモデル ・ [objective-c][iPhone]CoreDataを使う
ちょっと触ってみたけど、モデル書き出し方法とかで悩む・・・ で、わかりました!
(1) xcdatamodlを開く。 (2) エンティティ欄の【+】か、右クリックでエンティティを作成する。 今回、エンティティ名はSongとしました。
(3) プロパティを追加する。 author:String name:String rid:int64
iOS4.0の型はこれだけ選択できるようです
(4) 関連テーブルを作成する。 2〜3同様にScoreエンティティを作成しました。 まだデータモデル設計が全くできてないのですが、とりあえずサンプルなので以下のプロパティとしました。
barIndex:64
(5) Song、Scoreエンティティにそれぞれ関連を追加する。
Songにはscoreリレーション
Scoreにはsongリレーション 関連レコードなんで、本当はカスケードを設定した方がいいですけどとりあえず。
最終的にテーブルモデルはこんな感じになりました。
CoreDataの基礎 その1|CoreDataの基礎 その2|CoreDataの基礎 その3|CoreDataの基礎 その4
CoreDataの基礎 その1|CoreDataの基礎 その2|CoreDataの基礎 その3|CoreDataの基礎 その4
さて、せっかく作成したデータモデルですが、モデルファイルとして書き出さない事には意味がないですね。 この方法調べるのにちょっと時間かかりました(^^;)
(1) xcdatamodelを開いた状態にする。
(2) 新規ファイル...を開く。
(3) するとManaged Object Classって項目が現れます。 ちなみに、AppleScript classってのもありますが、何に使うかは不明です。 面倒くさい処理の際にスクリプト組むのでしょうか? もうAppleScriptは忘れましたが・・・
(4) ターゲット(DB)を選択する。
(5) 書き出したいモデルを選択する。
(6) モデルファイルが生成される。
これだけです。
実際に書き出されたコードを見てみます。
#import
@interface Song : NSManagedObject
{
}
@property (nonatomic, retain) NSNumber * rid;
@property (nonatomic, retain) NSString * author;
@property (nonatomic, retain) NSString * name;
@property (nonatomic, retain) NSSet* score;
@end
@interface Song (CoreDataGeneratedAccessors)
- (void)addScoreObject:(NSManagedObject *)value;
- (void)removeScoreObject:(NSManagedObject *)value;
- (void)addScore:(NSSet *)value;
- (void)removeScore:(NSSet *)value;
@end
NSManagedObjectを継承し、設定したプロパティやメソッドが記述されています。 関連レコードの追加削除もありますね。
次は、Xcodeで実際にデータ追加・削除等のコーディングをしていきます。
今回のmixiアクセス不能の件、memchachedのデーモンダウンが原因とのこと。
memchachedはDBクエリー負荷を軽減する為のメモリキャッシュ機能で、 大規模サーバのDB負荷軽減においてここ数年流行の機能です。
詳しくは、WEB+DB PRESS vol47を参照
今回のmixiの対応策としては
memchachedの設定で最大接続数を絞り、サーバを増やす方向で対処した
あと、繋がりにくいのは単にWebの帯域制限をかけてたものと見られます。
mixiの利用者数は2000万やそこら。 しかし5億以上とも言われているFacebook。 利用者が増えれば正比例以上にサーバ負荷となる。 でも、なぜFacebookは平然な顔で動作しているのか?
(1)数万台規模と言われてるサーバの台数 (2)RDBからの脱却
(1)に関しては桁違いとしか言いようがないw (2)に関しては、AmazonのDynamoとGoogleのBigTableを元にしたオープンソースの列指向分散データベース「Apache Cassandra」で、Facebook社がNonSQLデータベースで採用されているとの事。
SQLデータベース + memchachedの時代は終わった
いわゆる、NonSQLプログラミングです。 今回のmixiのトラブルで何か説得力のある言葉だと思った。
近年あまりにもデータが肥大化し、RDBのSQLで処理するには限界がきており、 Googleもここ数年KVS(Key Value Store)を推奨し技術提供している。
自分もRDBシステム開発している時に感じる部分があったり。 テーブル間のデータをSQLで複雑な処理させるより、プログラムや設計でカバーする方が圧倒的にパフォーマンスが良い事が多々ある。
また大規模サーバ負荷分散システムもここ数年で格安で構築できるようになっている。 [Apache]負荷分散、システム構成、memchached の勉強
とは言え、
既存のRDBデータをCassandraに移行するのはかなりの労力がいる
Twitterも現状MySQL + memchachedで運用しており、Cassandraに移行したいがなかなか踏み切れないらしい。
オイラも今後の新規開発に関しては、Cassandra等のKVS(Key Value Store)を視野に入れなきゃな?と思うのであった。
ちなみに、このサイトのシステムはPHP + PostgreSQL + Apacheです。 この規模じゃmemchachedすらいらないのですが(爆)、時間あったらこのサイトでもCassandraで試してみようと思います!
久々にPHPネタ。 と言うか、今更ながらOAuth接続を試してみる。
ライブラリ、サンプルはここから http://apiwiki.twitter.com/OAuth-Examples ※PHPライブラリ:http://github.com/abraham/twitteroauth
ちなみにGoogle-codeにもライブラリがあるが、コアのライブラリOAuth.phpは全く同じものだ。 Google-code oauth これが多分、デファクトスタンダードでしょう。
さて、実際にabraham-twitterのサンプルプログラムをちょちょっと改修してテストしてみました。 (リファクタリングしてないので見にくいですが・・・)
ダウンロードしたabraham-twitteroauthの中身 twitteroauthディレクトリがライブラリなので、プログラムで利用するパスに配置します。 ※その他のコンテンツはサンプルプログラムなので不要
まず、Twitterアプリを利用できるように認証の設定が必要です。
(1) Twitterにログインし連携アプリを開く。
(2) 開発者への欄のリンクを開く。 実際のURLは、http://twitter.com/apps
(3) 新しいアプリケーションを追加を開く。 実際のURLは、http://twitter.com/new
(4) 必要項目を入力する。
・アプリケーションのアイコン: 連携アプリに出てくるアイコンです ・アプリケーション名: 何でもよいですが、わかりやすくシンプルな方がいいでしょう ・アプリケーションの説明: ユーザに何をするのかを説明します ・アプリケーションのウェブサイトURL、所属会社/団体、サイト: ここら辺は任意で入力 ・アプリケーションの種類: クライアントアプリケーション = モバイルやデスクトップアプリならこれを選択 ブラウザアプリケーション = ブラウザアプリならこれを選択 要はリダイレクトをTwitter連携アプリでするか、自分のプログラムでするかの違いです。 ・コールバックURL: ブラウザアプリケーションを選択すると入力できます。 ・Default Access type: ユーザの書き込み権限を許可するかどうか? ・Twitterでログインする: Twitterでログインするかどうか? 通常はオンにしておくと楽でしょう。
(5) 設定が完了すると、Consumer keyとConsumer secretが発行されます。
※表示するhtmlソースは記載してません (1) twitteroauth/twitteroauth.phpのパスを通す。
require_once 'twitteroauth/twitteroauth.php';
(2) Twitterアプリの発行したConsumer keyとConsumer secretおよび、手動でコールバックするのであれば、認証後のURLを設定する。
define('CONSUMER_KEY', 'Consumer key');
define('CONSUMER_SECRET', 'Consumer secret');
define('OAUTH_CALLBACK', 'コールバックするURL');
(3) 現在のセッションから認証状況チェック まずPHPセッションを利用してトークンの状況を判断し、処理を振り分けます。
function oauth() {
if (empty($this->session['access_token']) || empty($this->session['access_token']['oauth_token']) || empty($this->session['access_token']['oauth_token_secret'])) {
$this->redirect_to('connect');
}
$access_token = $this->session['access_token'];
$connection = new TwitterOAuth(CONSUMER_KEY, CONSUMER_SECRET, $access_token['oauth_token'], $access_token['oauth_token_secret']);
$this->content = $connection->get('account/verify_credentials');
}
※$this->redirect_to()は、リダイレクトする独自関数
セッションにトークンがなければ認証画面(./connect)にリダイレクトします。 トークンがあれば、TwitterOAuthのget('account/verify_credentials')でTwitter情報を取得し、$this->contentに割り当てます。
(4) セッションクリア処理で、access_token、status破棄し認証画面にリダイレクト
function clear() {
unset($this->session['access_token']);
unset($this->session['status']);
$this->redirect_to('connect');
}
(5) 認証画面
function connect() {
if (!defined('CONSUMER_KEY') || !defined('CONSUMER_SECRET')) {
echo('consumer_key、consumer_secretが設定されていません');
exit;
}
}
念のためCONSUMER_KEY、CONSUMER_SECRETをチェックしてから認証画面を表示します。 ※表示するhtmlソースは記載してません 「Twitterに接続する」をクリックすると./redirectへリンクします。 ※$this->sessionは、セッション管理の独自プロパティで、$_SESSIONみたいなものです
(6) Twitter連携アプリへの認証処理 認証画面からアクセスされる処理です。
function redirect() {
$connection = new TwitterOAuth(CONSUMER_KEY, CONSUMER_SECRET);
$request_token = $connection->getRequestToken(OAUTH_CALLBACK);
$this->session['oauth_token'] = $token = $request_token['oauth_token'];
$this->session['oauth_token_secret'] = $request_token['oauth_token_secret'];
switch ($connection->http_code) {
case 200:
$url = $connection->getAuthorizeURL($token);
header("Location: {$url}");
break;
default:
echo 'Twitterに接続できません';
}
}
TwitterOAuthのgetRequestToken()でコールバックURLを設定しTwitter連携アプリへ認証処理をします。 認証が成功すると「oauth_token」「oauth_token_secret」が返されるのでセッションに保存します。 またgetAuthorizeURL()でトークンからコールバックURLを取得&リダイレクトします。
(7) コールバック処理
function callback() {
if (isset($_REQUEST['oauth_token']) && $this->session['oauth_token'] !== $_REQUEST['oauth_token']) {
$this->session['oauth_status'] = 'oldtoken';
$this->redirect_to('connect');
}
$connection = new TwitterOAuth(CONSUMER_KEY, CONSUMER_SECRET, $this->session['oauth_token'], $this->session['oauth_token_secret']);
$this->session['access_token'] = $connection->getAccessToken($_REQUEST['oauth_verifier']);
unset($this->session['oauth_token']);
unset($this->session['oauth_token_secret']);
if (200 == $connection->http_code) {
$this->session['status'] = 'verified';
$this->redirect_to('index');
} else {
$this->redirect_to('connect');
}
}
まず、不正なoauth_tokenでないか判別します。 TwitterOAuthのgetAccessToken($_REQUEST['oauth_verifier'])でaccess_tokenを取得し、oauth_tokenを破棄します。 接続がOK(HTTP 200)なら認証後の画面に、失敗した場合は認証画面にリダイレクトします。
(8) 認証後の画面の表示
function index() {
$this->oauth();
}
認証が通ればTwitter情報を表示します。 ※oauth()で$this->contentにTwitter情報が割り当てられているはず
CoreDataの基礎 その1|CoreDataの基礎 その2|CoreDataの基礎 その3|CoreDataの基礎 その4
次はCoreDataの基本部分の実装ファイルをみていきます。
CoreDataにチェックしてWindow-based Applicationプロジェクトを作成するとAppDelegateに以下のような雛形が作成されます。
#import "SongAppDelegate.h"
@implementation SongAppDelegate
@synthesize window;
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
[window makeKeyAndVisible];
return YES;
}
- (void)applicationWillResignActive:(UIApplication *)application {
}
- (void)applicationDidEnterBackground:(UIApplication *)application {
}
- (void)applicationWillEnterForeground:(UIApplication *)application {
}
- (void)applicationDidBecomeActive:(UIApplication *)application {
}
- (void)applicationWillTerminate:(UIApplication *)application {
NSError *error = nil;
if (managedObjectContext_ != nil) {
if ([managedObjectContext_ hasChanges] && ![managedObjectContext_ save:&error]) {
NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
abort();
}
}
}
#pragma mark -
#pragma mark Core Data stack
- (NSManagedObjectContext *)managedObjectContext {
if (managedObjectContext_ != nil) {
return managedObjectContext_;
}
NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
if (coordinator != nil) {
managedObjectContext_ = [[NSManagedObjectContext alloc] init];
[managedObjectContext_ setPersistentStoreCoordinator:coordinator];
}
return managedObjectContext_;
}
- (NSManagedObjectModel *)managedObjectModel {
if (managedObjectModel_ != nil) {
return managedObjectModel_;
}
NSString *modelPath = [[NSBundle mainBundle] pathForResource:@"Song" ofType:@"momd"];
NSURL *modelURL = [NSURL fileURLWithPath:modelPath];
managedObjectModel_ = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
return managedObjectModel_;
}
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator {
if (persistentStoreCoordinator_ != nil) {
return persistentStoreCoordinator_;
}
NSURL *storeURL = [NSURL fileURLWithPath: [[self applicationDocumentsDirectory] stringByAppendingPathComponent: @"Song.sqlite"]];
NSError *error = nil;
persistentStoreCoordinator_ = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];
if (![persistentStoreCoordinator_ addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:&error]) {
}
return persistentStoreCoordinator_;
}
#pragma mark -
#pragma mark Application's Documents directory
- (NSString *)applicationDocumentsDirectory {
return [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
}
#pragma mark -
#pragma mark Memory management
- (void)applicationDidReceiveMemoryWarning:(UIApplication *)application {
}
- (void)dealloc {
[managedObjectContext_ release];
[managedObjectModel_ release];
[persistentStoreCoordinator_ release];
[window release];
[super dealloc];
}
アプリケーション終了時にデータ(ManagedObjectContext)変更があった場合、保存エラー処理を記述するようです。
NSFetchedResultsControllerのインスタンスです。 ここではgetterの役割でしょうか? NSManagedObjectContextインスタンスが生成されていなければ、新しく生成します。 その際、既に生成済みのNSPersistentStoreCoordinatorをsetします。
これもgetterでしょう。 NSPersistentStoreCoordinatorが生成が生成されていなければ、新しく生成します。 その際、sqliteファイルをNSURLで指定し、initWithManagedObjectModelでモデルファイルとして生成します。
アプリのデータ保存パスを返します。
忘れずにメモリを解放します。
Window-based Applicationではここまでです。 Navigation-based Applicationで作成した場合は、datetimeを値としたレコード処理がもれなくついてきます。 勉強には良さそうですが、いろいろと修正しなくちゃいけない気もしたり・・・ いや、まだ深く突っ込んでないから知りませんが(^^;)
次は、xcdatamodelを使ったモデラーの使い方をやってみます。
CoreDataの基礎 その1|CoreDataの基礎 その2|CoreDataの基礎 その3|CoreDataの基礎 その4
CoreDataの基礎 その1|CoreDataの基礎 その2|CoreDataの基礎 その3|CoreDataの基礎 その4
iphoneのデータ管理はSDK3.0になってからCoreDataが推奨となっている模様です。 もともと、AppleのWebObjectsってのを会社でやってて、「EO Modeler」と同じかな? SQLを書かなくてもデータモデルができると言うのは何となく想像はつきますが・・・。
まずデータオブジェクトを扱うのに出てくる「キーバリューコーディング」
NSString *name = [managedObject valueForKey:@"name"]; [managedObject setValue:@"Yoo" forKey:@"name"];
とデータストアから取り出したデータをkeyとvalueを取得、設定します。 CoreDataのデータストアタはデフォルトSQLiteです。 と言ってもSQLは原則書くことはありません。 ただ、データ設計に関してはリレーショナルデータベースの知識は多少必要かもしれません。
ちなみに、SQLiteのデータストアの場所をパーシステントストアと呼ぶようです。 CoreDataと仲介するオブジェクトはNSMnagedObjectContextです。 (WebObjectsだとEOEdtingContextにあたるものでしょうか?)
では実際にプロジェクトを作成してみます。
Window-based Applicationを選んで、Use Core Data For storageにチェックを入れて作成するだけです。
すると、Resourcesに.xcdatamodelファイルが作成されます。
ファイルを開くとエディターらしきものが開きます。 おお!見た目だけで便利そうすねw
このエディタの使い方はまた後で書く事にして、コーディングの方をみていきます。
Window-based Applicationの場合、ある程度の雛形で作成されますが、まずはヘッダーファイルからみていきます。
#import
#import
@interface SongAppDelegate : NSObject {
UIWindow *window;
@private
NSManagedObjectContext *managedObjectContext_;
NSManagedObjectModel *managedObjectModel_;
NSPersistentStoreCoordinator *persistentStoreCoordinator_;
}
@property (nonatomic, retain) IBOutlet UIWindow *window;
@property (nonatomic, retain, readonly) NSManagedObjectContext *managedObjectContext;
@property (nonatomic, retain, readonly) NSManagedObjectModel *managedObjectModel;
@property (nonatomic, retain, readonly) NSPersistentStoreCoordinator *persistentStoreCoordinator;
- (NSString *)applicationDocumentsDirectory;
@end
オブジェクトデータモデルのことで、モデルファイルでEntityを管理する。 .xdatamodelそのものぽいけど、ファイルタイプはmomdのようです。
NSManagedObjectContext(xdatamodel)から作成されるデータストレージ。 addPersistentStoreWithTypeで、データベースファイ、Data Storageの種類を選択することができる(SQLiteが一般的か?)
NSManagedObjectModel、NSPersistentStoreCoordinatorから取得したデータオブジェクトをメモリ内で管理する。 実際にデータを操作する場合は、NSManagedObjectContextを介してコーディングすることになる(であろう)。
managedObjectContext_、managedObjectModel_、persistentStoreCoordinator_を隠蔽化して、各getterを用意しています。
次は実装ファイルをみてきます。
CoreDataの基礎 その1|CoreDataの基礎 その2|CoreDataの基礎 その3|CoreDataの基礎 その4
会社のWikiには書いてあって、コマンドを忘れてしまうのでメモ てか、リポジトリ作成も自動化したいところだが・・・・
cd /var/svn svnadmin --fs-type fsfs create プロジェクト名 chown -R apache:apache プロジェクト名
apacheユーザのアクセス権限&グループ変更すれば、最後は無駄かな?
あとOSXのSVNクライアントって、無料でいいのが見つからない。 TortoiseSVNのOSX版でないかな?(-_-)