Study CoreData 17 ~想えば遠くへ来たもんだ。~

みなさん、おばんどす〜ぅ。
 
 
いきなりですが先日、こんな記事を拝見させて頂きました。
(このシリーズは、毎日必ず更新するために数日先の分まで書いているので
情報は少し前のものになります。)

「売れる iPhone アプリ」にするための151のヒント。
「売れる iPhone アプリ」にするためのAppBank攻略法
 
 
もとまかさんの個人的な見解でありながら、そうだろうなぁと納得する部分も多く 改めて

『だからこそ、挑戦し甲斐があるんだ!』

なんて思ったりもしました。

とは言っても、『僕の考えとは違うなぁ』とか『コレも必要でしょ?』というところもあったりもして…


 
 
僕はまだ”未リリースの開発者”なので実体験として書く事は出来ませんが、
生意気にもちょこっと書かせてもらいたいなぁと思います<(_ _)>
 
 
『本当に”機能”がシンプルな方が良いの?』
 
 
というのも僕は、AppStroreはもう
アイデア”だけ”で勝負できる世界ではなくなったんじゃないか?
って思っているからです。

そんな持論から僕は、機能のシンプルさを最重要視するのではなく
操作性を極限までシンプルにすること
にこだわりたいと思ってます。
 

そして、生まれたアイデアを
『これなら絶対売れる!! 売れないはずがないっ!』
って思い込めるようになるまで、ひたすらブラッシュアップしていく。

(当然、作りながら。)

もちろんこういったやり方だと”量産”する事は出来ませんし、
「数打ちゃ当たる」的な手法を取るのは難しいと思います。
でも僕は、
確実に狙いすました標的にDOGAAAAN!!と打ち込みたい
って思うんですよね。
 
 
ただどんなやり方を選ぶかは、開発者の考え方や性格的なものもあると思いますので何がベストなのかはそれぞれだと思います。

…ってコトで、あまり細かく書いてると勉強が進まないのでこの辺で(^〜^;)

ご清聴ありがっしたっ!<(_ _)>

注意:投稿者自身もCoraDataについて勉強中のため、このシリーズには誤りが含まれている可能性があります。もし、間違いに気付かれた方はコメント欄もしくはtwitterなどでご指摘いただけると幸いです<(_ _)>
また、開発環境はXcode3.2.3 iPhone SDK 4です。実機でのテストなどは自己責任でお願いいたします。

 
 

1. 夏の夜の怪奇現象

まず今日は、前回の最後に見た『No Category無限増殖現象!?』を治します(^〜^;)

その問題の正体は[RootViewController]の…

『おまえだぁ!!』

キャ〜〜〜〜〜っっ!!

ってコトで(^^;)、ここで毎回”No Category”って名前のカテゴリを作っちゃってたのが原因ですね。
では、どうすれば良いんでしょうか?

1. “No Category”なエンティティを全Categoryを対象に検索。
2. 見つかればそれをセット。
3. なければ新規で作ってセット。

こんな感じで良いんじゃないですかね?

今回は以下のようなメソッドを作ってみました。

ざっと説明しますね。

まず、今自分が持っているcategoryが引数で送られてきた名前と同じなら、何もせずに終了します。
次に前回作った[allRelationshipsFor…]を使って全Categoryを取得。
そしてその全Categoryのnameをチェックして、引数のnameと同じものがあればそれを[insertCategory]へ代入しておきます。

その結果[insertCategory]がnilなら、同一のものがないという事になるので新規に用意して[insertCategory]へ入れます。

で、最後にself.categoryにセットして完了!
 
 
ついでに対多関連である[tags]の場合はこんな感じになるんじゃないかと。

こっちの場合は本来なら一番最初に

	BOOL wasAlreadySet;
	
	for (Tag *aTag in self.tags) {
		if ([aTag.name isEqualToString:name])
			wasAlreadySet = YES;
	}
	
	if (wasAlreadySet == YES)
		return;

// wasAlreadySet = NO なら以下の処理へ...

こんな感じで、既に同じ名前のTagがあれば処理をしないようにするべきなんだろうと思いますが省略しちゃってます^^;
恐らく既にセットしてあるTagが[addTagsObject:]に渡された場合、そのメソッドの中では処理されずにreturnされると思うので、重複する事はないだろうと。
 
 
では、先に説明した2つのメソッドを[Task.m]に追加してください。
(※しつこいようですが宣言も忘れずに。)
([setTagWithName:]は後ほど使います。)
 
 
それらを入れ終わったら、例の事件現場をお掃除します。
(画像でハイライトされていた箇所を以下のコードと入れ替えます。)

			if (!editedTask.category) {
				[editedTask setCategoryWithName:DEFAULT_CATEGORY];
			}

 
これでオッケーですね!
次に行きましょう。
 
 

2. 知られてはいけない秘密のカテゴリー

お次も同じく前回の最後で説明した問題点の修正です。
ユーザーに違和感を感じさせてしまう可能性がある
“No Category”という名前のカテゴリーをリストに表示しないようにします。
 
 
今回はこんな方法でそれを実現しようと思います。

1. Categoryクラスに[name]が”No Category”かどうか?を返すフラグを追加。
2. そのフラグがYESなら表示するデータソース[listObjects]から取り除く。

言葉で説明するだけだと簡単そうですね。
 
 
まず、[Category.h]でフラグを宣言します。

それを実装します。

 
 
そこまで出来たら、今度は“SelectableViewController”の[setDataSource]内
[isSecret = YES]なオブジェクトを取り除く。
という処理をするのですが、
それを実現するのが『NSPredicate』(述語)です!
 
 
このNSPredicateについては、
『Study CoreData』の初めの方(fetchedResultControllerのフェッチリクエストのところ)でちょこっとだけ触れたことがありましたが覚えてますか?

その時にこのクラスについて
Macのスポットライト検索

を例に出してましたが詳しくは全く触れてませんでしたね。
 
 
では、先に実装するコードを見てみてください。

これで取得した[objects]の中から[isSecret = NO]のものだけを取り出せます。

[predicateWithFormat:]の書式は[stringWithFormat:]とよく似ていますね。
ですが[predicateWithFormat:]の場合は
@””の中に入る文字列はオブジェクトのKeyとして認識してくれるようです。
 
 
つまりこの場合の条件は
@”Key == value”
となっています。

そしてNSArrayに[filteredArrayUsingPredicate:]することで、その条件に当てはまるデータのみの配列を返してくれます。
 
 
ちなみにフェッチリクエストにセットする場合は…


NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
	
// エンティティやソートデスクリプターのセットなど...
	
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"isSecret == %d", NO];
[fetchRequest setPredicate:predicate];

コレだけです。

あとpredicateの生成部は、下のように書いても同じ処理になります。

NSPredicate *predicate = [NSPredicate predicateWithFormat:@"%K == %d", @"isSecret", NO];

この他にもOR(||)やAND(&&)などを使ってさらに細かく設定するなど色々と出来るんですが、今後検索機能を実装する時にも使うので、その時にもう少し詳しく説明したいと思います。
 
 
それじゃ、そのNSPredicateを加えてビルドしてみましょう!
これで、”No Category”は表示されなくなったはずです。
 
 

3. 新しい関連をセット可能にする

次にお待ちかねの『新規リレーションシップの追加』に向けて実装
していこうと思うのですが、
先にそれを処理するためのボタンアクションを確認しておきましょう。

まとめるとこんな感じです。

[[ テキストフィールド非フォーカス時 ]]
・[Addボタン]もしくはテキストフィールドのタップでキーボードを表示
・[Add]を[Done]に変更。
・[Edit]を[Cencel]に変更。
・リストの全面に半透明の[Cancelボタン]を表示。

[[ テキストフィールドフォーカス時 ]]
・[Doneボタン]もしくは[リターンキー]のタップでキーボードを非表示に。(新規追加)
・[Cancel]もしくはリスト全面の[Cancelボタン]のタップでキーボードを非表示に。(キャンセル処理)
・[Done]を[Add]に戻す。
・[Cencel]を[Edit]に戻す。
・リスト全面の[Cancelボタン]を非表示に。

ってことは、リスト全面に表示する[Cancelボタン]用のインスタンスも追加しなきゃですね。
 
なので、以下をヘッダファイルに加えておいてください。

UIButton *_backgroundCancel;

 
 
そしたら実装していきます。

まずは一番簡単そうなキャンセル処理から。


#pragma mark Button Action
- (void)cancelButtonTapped:(id)sender {
	
	if ([_textField canResignFirstResponder])
		[_textField resignFirstResponder];
	_textField.text = nil;
}

簡単ですね♬ キーボードを非表示にして、テキストフィールドに入れられた文字列を削除してます。
 
 
お次ぎは先にボタンの切り替え用メソッドを。ちょっと長いです^^;


#pragma mark -
#pragma mark Add New Category / Tag
- (void)exchangeButtonsState {
	
	if (!_backgroundCancel) {
		
		CGRect buttonFrame = self.tableView.bounds;
		CGFloat originY = self.tableView.tableHeaderView.bounds.size.height;
		buttonFrame.origin.y = originY;
		buttonFrame.size.height -= originY;
		
		// 半透明のキャンセル用ボタン
		_backgroundCancel = [UIButton new];
		_backgroundCancel.frame = buttonFrame;
		_backgroundCancel.backgroundColor = [UIColor blackColor];
		_backgroundCancel.alpha = 0.8f;
		[_backgroundCancel addTarget:self action:@selector(cancelButtonTapped:) 
					forControlEvents:UIControlEventTouchDown];
		[self.tableView addSubview:_backgroundCancel];
		[_backgroundCancel release];
		
		_backgroundCancel.hidden = YES;	// 非表示にしておく
	}
	
	if (!_currentRightBarItem) {
		// ナビバー用のキャンセルボタン
		UIBarButtonItem *cancelButton = 
		[[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemCancel 
													  target:self 
													  action:@selector(cancelButtonTapped:)];
		self.currentRightBarItem = [cancelButton autorelease];
	}
	
	// ボタンの表示を切り替え
	_newObjectSaveButton.hidden = !_newObjectSaveButton.hidden;
	_backgroundCancel.hidden = !_backgroundCancel.hidden;
	
	// ナビバーボタンの切り替え
	/*! 切り替え前のボタンを保持してリユース */
	UIBarButtonItem *item = self.navigationItem.rightBarButtonItem;
	self.navigationItem.rightBarButtonItem = _currentRightBarItem;
	self.currentRightBarItem = item;
}

ここではまず、ふたつのキャンセルボタンをつくってます。
その後で、“ナビバーのボタン”“ツールバーのボタン”“リストを覆うcancelボタン”の表示をすべて切り替えます。
 
 
そして、その切り替えを呼ぶのは…


#pragma mark -
#pragma mark TextField Delagate
// テキストフィールドフォーカス時
- (void)textFieldDidBeginEditing:(UITextField *)textField {
	[self exchangeButtonsState];
}
// テキストフィールド アンフォーカス時
- (void)textFieldDidEndEditing:(UITextField *)textField {
	[self exchangeButtonsState];
}

テキストフィールドのデリゲートメソッドを使って、“編集開始時”と”編集終了時”に呼び出します。
 
 
そして肝心のツールバーのボタンがタップされた時の処理ですが、
僕のコードを見る前に是非、実装してみてくださいね。
メソッド名は[- (void)toolBarButtonTapped:(id)sender]で。

やることは…
・テキストフィールドが編集中でないなら
  1. テキストフィールドをフォーカス。

・テキストフィールドが編集中なら
  1. 新しいエンティティをセット。
  2. データソースを更新。
  3. テーブルビューを更新。
  4. CategoryリストならDetailViewに戻る。
  5. フォーカスを外す。
  6. テキストフィールドのテキストを削除。
 
 
書けたら次のコードを見てみてくださいね。

今までやってきた事がほとんどなので、特に説明は不要かと。
ちなみに[EditaTypeCategory]の場合は新規カテゴリーをセットしたらすぐにPopしています。
こうする事でユーザが”BackButton”をタップする手間がいらなくなります。
 
 
あとは、このアクションを各ボタンにセットすれば完璧でっす!!

 
んぢゃ、久しぶりに…

せ〜〜ぇのっ!
 
 
ビルダンゴーォォ!!
 
 

4. 想えば遠くへ来たもんだ。


(あら…順番が…^^;)

どうですか?
みなさんの『dotodo』も新規カテゴリーやタグが入れられるようになりましたか??

まだ、セルの削除など実装しなければいけないところや
実はデッカイ落とし穴が待ち受けてたりもします。
 
 
…ですが、想えば『Study CoreData』を開始してからもうすぐ3週間が過ぎようとしています。

ここまで、一緒に頑張ってくれたみなさんには
『思ってたよりスムーズに出来た!』
『使い方が分かってきたよ。』
って感じてもらえてたらウレシイなぁって。

 
 
このシリーズが終わったら、僕は『TapDays』(開発中のアプリ)に没頭して行こうって思ってます。

恐らくあと10エントリまでいく事はないと思うので、是非最後までおつきあいのほど<(_ _)>
 
 
…とそんなこんなで明日からはさらに佳境にさしかかっていきます!

んだば、しーゆぅとぅもろ〜〜♬

広告

Study CoreData 17 ~想えば遠くへ来たもんだ。~」への13件のフィードバック

  1. ピンバック: [夕刊] 8月のApple Storeイベント( @monokakido ) 、オフ会告知開始。早く参加申請済まそうぜ!

  2. Jacminikさんこんにちは

    いつもお世話になります。tomtomです。

    たびたびお手数をおかけしますが、またまた行き詰まってしまいました。

    新規タスクを作ってDetailViewでTitleとDueDateの設定まではうまくいきますが、SelectableViewの動きがめちゃめちゃになっています。
    SelectableViewでの編集はできるのですが、DetailViewに戻った時に【main.m】の「int retVal= …」の行で”EXC_BAD_ACCESS”で止まってしまいます。

    ● DetailViewからSelectableViewに移動して、何もしないでそのまま戻ると必ずこの現象が発生します。
    ● タグやカテゴリを追加する時はこの現象が起きたり起きなかったりします。
    ● チェックマークを変更した時も必ず発生します。

    一週間ほど前からなんとか自分で解決しようと頑張ってみましたが、お手上げ状態です。

    ご教授よろしくお願いします。

    • tomtomさん。こんにちわ!
      二回目のコメントありがとうございます<(_ _)>

      御質問の”EXC_BAD_ACCESS”の原因ですが、ごめんなさい。こちらでは限定することができません。
      ただ、SelectableViewからのPop時に起こるようですので、もしかしたらPop前のデータ保存時あたりが怪しいかなぁ?と。
      なので、その辺りをログなどでしらべてみると良いかもしれませんね。

      それと”EXC_BAD_ACCESS”ですが、コレが出た時の原因のうち一番多いのは解放済みのオブジェクトにアクセスしてしまっているパターンですので、この辺りはInstrumentsでNSZonbieを調べてみると良いと思います。

      >> 【main.m】の「int retVal= …」の行で”EXC_BAD_ACCESS”

      とのコトですが、これは別スレッドからメインループに戻ろうとする時に発生する(とある方に教えて頂きました^^;)ようなので、mainに戻る前のスレッドで問題があるということになります。

      もし”EXC_BAD_ACCESS”が出てもXcodeが生きている(プロジェクトが終了されていない)状態であれば、デバッグ画面のThreadsの辺りを見てみると分かるかもしれません。

      。。と、そんな感じでしか答えられないのですが調べてみてくださいね。

  3. jacminikさん。こんにちは

    早速の回答有り難うございました。

    NSZonbieで調べたところ以下のように表示されましたが、内容がよくわかりません。
    Zombie Messaged
    An Objective-C message was sent to a deallocated object(zombie) at address: 0x7a5f160.→
    →をクリックして問題のありそうな所を調べてみると
    DetailViewControllerのdidSelectRowAtIndexPathメソッドの中の
    [self.navigationController pushViewController:editController animated:YES];の行が強調表示されて右端のほうに「8 Hits 80%」と表示されます。

    デバッグ画面のスレッドの辺りを見てみましたが、
    どうも【0 objc_msgSend】というのが怪しいと思います。
    詳細をみると
    0x0111c09b mov 0x8(%edx),%edi
    と訳の分からないアドレスみたいなものが表示されます。

    分からないことだらけで申し訳ありませんが、暇を見て回答していただけると、ありがたいです。

    話は違いますが、jacminikさんの本職はデザイナーなのですか?
    AppBankのアイコンはjacminikさんが作ったのですね。
    驚きました。
    売れそうなアプリができたらデザインを是非お願いしたいと思います。
    (現在Liteバージョンを含め似たようなアプリを10本ほどリリースしましたが、売上はさっぱりです。)

    • tomtomさん、こんにちわ!

      頂いた内容を見ると、予想どおり解放済みのオブジェクトへのアクセスが一因のようですね。(他にもあるかもしれませんが。。^^;)

      ただSelectableViewからのPop時に発生するバグなのにSelectableViewへのPush部分がInstrumentsに表示されるとは。。。?

      Instrumentsを上手く使えばどのオブジェクトが問題かすぐに分かる可能性は高いのですが、ここでその使い方を書くのはムリがあるので<(_ _;)>

      とりあえず別の原因の追い込み方法としては、ひたすらNSZombieになってしまっているオブジェクトを見つけることですかね。
      なので、バグ発生前の部分に辺りを付けていくつかの場所でログを仕掛けてみてください。
      NSLog(@”ログテスト_1″)/NSLog(@”ログテスト_2″)といった感じで。

      そうするとどこかの場所でログが出力される前にBAD_ACCESSになると思いますので、最後に出力されたログと出力されなかったログの間にさらに細かくログを仕掛けてビルド。。。コレを繰り返して発生箇所を見つけます。

      で、オブジェクトが解放済みかどうかを確認するには
      NSLog(@”オブジェクト1(%p)”, aObject);
      といった感じで個々のオブジェクトを調べます。問題なければ%pの部分にアドレスが表示され、解放済みならばそのログでBAD_ACCESSになると思いますのでそれが問題のオブジェクトです。

      と、そんな感じでしかお答えできませんがガンバってみてくださいね!

      それとアイコンデザインの受注に関しては大歓迎です!
      詳しくはこちらに載ってますので。
      http://www.edensvision.com/

      それにしてもすでに10本リリース済みとは凄いですね!!
      僕も頑張らなきゃです(^〜^;1)

  4. jacminikさん。こんにちは
    分かりやすく細かい説明有り難うございます。

    お騒がせしました。
    NSZombieの使い方が間違っていました。
    再度調査したところ、SelectableViewController.mのdeallocの中の
    self.listObjects = nilの行がひっかかりました。
    なぜなのか原因はわかりませんが、これをコメントアウトしたらきちんと動くようになりました。
    でも、propertyでretainしているので、このままでいいのかちょっと心配です。

  5. jacminikさん。いつもお世話になります。tomtomです。

    このブログを参考にしながらアプリを作っていますが、一つ教えていただきたい事があります。
    私のアプリでは、各レコードにお気に入りのBOOL値をセットしてありますが、お気に入りだけを抽出するための方法がよく分からず、RootViewControllerのサブクラスとしてfetchedResultsControllerの部分を変更したFavoriteViewControllerを作りました。
    FavoriteViewControllerへの遷移はタブで切り替えます。
    とりあえず今のところはきちんと動いていますが、こんなやり方ってありですか?
    何か致命的な間違いをしたのではないかとものすごく心配です。

    もし他に適切な方法をご存知でしたらご教授をお願いできますか?
    お忙しいところ申し訳ありませんが、お返事をいただけると助かります。

    • tomtomさん。お久しぶりです!

      頂いたコメントの仕様でもちゃんと期待通りに動いているのなら、特に問題はないと思いますよ。
      コメントの内容だけだと2つのViewControllerの違いがよく分からないのですが。。。^^;

      ただ、お気に入りされたアイテムだけを表示させるのか?
      もしくは、すべてのアイテムを表示してそれぞれお気に入りの状態(YES/NO)を表示するのか?
      によってデータの取得方法は変わってくると思います。

      前者なら、メインのViewControllerでNSPredicateを使って”isFavorite = YES”なものを取り出して、それだけ別の画面に渡しても良いかもです。

      後者なら、メイン画面ですべてのデータは取得済みだと思いますので、当然お気に入りの状態もそのまま表示してあげれば良いだけですし。。
      僕なら
      『ひとつのViewControllerの中でなにかアクション(ボタンを押すなど)があった時に、お気に入りの状態が表示される。』
      といった仕様にするかなぁと。

      ちょっとイメージが分からないので、御質問に答えられていないかもしれませんが、そんな感じです(^〜^;

  6. さっそくの回答ありがとうございます!

    RootViewControllerにはすべてのアイテムを表示してFavoriteViewControllerにはお気に入りがYESのものだけを表示しています。行がタップされたらRootViewControllerと同じように編集画面へ遷移するようになってます。

    FavoriteViewControllerのfetchedResulutsControllerのほうにはNSPredicateを追加しました。
    念のため新規の追加ボタンは非表示にしましたが、RootViewControllerで大元のmanagedObjectContextとprovisionalContextを宣言してAppDelegateから取得しているのでその辺が心配でした。

    じつは私もjackminikさんのおっしゃる通りメインのRootViewControllerにボタンを作ってみたり、一番上の行をタップするとお気に入りの画面を表示させようとかいろいろやってみましたが、ハマリまくって実現できなかったので、この方法しかなくなりました。

    なにか一つを直すと他のところが動かなくなり、そこを直すとまた他のところが動かなくなったり、いままで正常に動いていた過去のバージョンが全て動かなくなったり、毎日がデバッグの連続です。

    画像関係には本当に苦労しました。
    メインの行にはサムネイルを表示し、編集画面のサムネイルをタップすると普通のサイズの画像を表示していますが、カメラでとった写真が重すぎて保存と表示に時間がかかりすぎ、これでは実用にならないと思い何とか画像を軽くしようと試みましたが、結局対応ができず、画像はplistに保存してCoreDataには画像へのパスを保存するやり方でなんとか解決しました。
    パスを保存してそれから画像を表示させる方法とかわからず、画像関係を解決するまで1ヶ月くらいかかりました。

    以前iPhoneCoreDataRecipesやCoreDataBooksのコードを見た時にはえらく複雑でほとんど意味がわかりませんでしたが、jackminikのブログで勉強したおかげである程度わかるようになりました。ありがとうございました。

    本当はテーブルを階層構造にしたかったのですが、ググりまくっても見つからず諦めました。
    もしご存知のサイトがありましたら教えて下さい。
    英語のサイトでも絵とコードが書いてあればなんとかなると思います。

    • tomtomさん。
      このブログ連載がお役に立てたようで嬉しい限りです^〜^

      CoreDataの階層構造について紹介出来るサイトは知らないのですが、単純に以下のような構造にすれば、Mac上のフォルダ管理に近い実装ができますよ。

      例として『アルバム(フォルダ)ごとに管理出来る写真整理アプリ』を作るとすると。。。

      1. エンティティはAlbum(フォルダ的役割)とPhoto(各写真の情報含む)
      2. AlbumにはalbumID、title、descriptionなどの属性を持たせる。
      3. PhotoにはphotoID、memo、created、tag、geotagなどの属性を持たせる。(※photoIDは重複のないユニークなIDにしておけば別のアルバムに移動させてもダブらなくて安全)
      4. AlbumとPhotoを一対多関連で紐付ける。

      これでフォルダ(Album)とファイル(photo)のような階層構造になると思います。

      ご参考になれば幸いです。

  7. アドバイスありがとうございます。
    大改造になると思うのでバージョンアップにて対応しようと思います。

    これからも引き続きお世話になると思いますので、よろしくお願いします。

  8. 質問お願いします。
    coredataを使ったアプリを作っているのですが、
    前の章で、NoCategoryが大量発生したのと同じ現象が起こっています。

    isEqualToStringで同じ値があるかどうかを調べるところはわかったのですが、
    すでに名前の同じカテゴリがあった場合、どのように既存のカテゴリをセットするのか
    イマイチわかりません。

    自分はcoredataに保存するときに、
    [newManagedObject setValue:hoge forKey:@”hoge”];
    を使っているんですけど、この場合ってこのブログで書かれているのとは違う方法をとらないと
    いけないですかね?

    • ちなみにnewManegedObjectはこういう風に作っています。

      NSManagedObjectContext *context = [fetchedResultsController managedObjectContext];
      NSEntityDescription *entity = [[fetchedResultsController fetchRequest] entity];
      NSManagedObject *newManagedObject = [NSEntityDescription insertNewObjectForEntityForName:[entity name] inManagedObjectContext:context];

コメントを残す

以下に詳細を記入するか、アイコンをクリックしてログインしてください。

WordPress.com ロゴ

WordPress.com アカウントを使ってコメントしています。 ログアウト / 変更 )

Twitter 画像

Twitter アカウントを使ってコメントしています。 ログアウト / 変更 )

Facebook の写真

Facebook アカウントを使ってコメントしています。 ログアウト / 変更 )

Google+ フォト

Google+ アカウントを使ってコメントしています。 ログアウト / 変更 )

%s と連携中