2013/03/10

NSNotificationCenterの通知を受け取るときにちょっとハマったケース

非同期で処理を行いたい時には欠かせないNSNotificationCenterですが、とあるケースで通知が受け取れずにハマったので、ブログに書いておこうと思います。

NSNotificationCenterを使う最もポピュラーなケースとしては、非同期で通信を行い(NSObjectのサブクラス等)、受け取った結果を画面(UIViewControllerのサブクラス)に通知して反映する場合だと思います。大抵のサンプルもそれを前提にしていますよね?

今回やりたかったケースでは、画面と通信を行うクラスの間に通信を管理するクラスを作り、画面⇄管理⇄通信というふうに連携します。つまりNSObject→UIViewControllerと通知を投げるパターンの他、NSObject→NSObjectと通知を投げるパターンが発生するのです。

このNSObjectからNSObjectへの通知がくせ者でした。

例えば、下記のように通知を投げるとします。
NSNotification *notification = [NSNotification notificationWithName:@"DownloadComplete" object:self];
[[NSNotificationCenter defaultCenter] postNotification:notification];
通常であればこのように受取側を書くと思います。
NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter];
[notificationCenter addObserver:self selector:@selector(receiveDownload) name:@"DownloadComplete" object:nil];
ところが、この記述ではreceiveDownloadメソッドは呼ばれません。(エラーも出ません)

色々調べた結果、今回のケース(NSObject→NSObject)では受取側を下記の様に記述しなければならないようです。
NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter];
[notificationCenter addObserverForName:@"DownloadComplete"
                                        object:nil
                                         queue:nil
                                    usingBlock:^(NSNotification *note) {
                                        [self receiveDownload];
                                    }];
addObserver:selector:name:object:でなくaddObserverForName:object:queue:usingBlock:の方を使う必要があったようです。
これでDownloadCompleteの通知が投げられた際に、receiveDownloadメソッドが呼ばれるようになりしました。

めでたし、めでたし。

2012/11/22

XCodeプロジェクトに Facebook SDK for iOS を同梱する

https://developers.facebook.com/docs/getting-started/facebook-sdk-for-ios/3.1/
ここ↑のgetting-startedのインストール手順だと、SDKは~/Documents/FacebookSDKにインストールされて、プロジェクトとSDKとはリンクされてるだけです。

SDKの本体は、~/Documents/FacebookSDK/FacebookSDK.framework になるので、
Finder上で組み込みたいプロジェクト(.xcodeprojと同じ階層)にコピーしてから、同じようにプロジェクトに追加します。

XCodeで、TARGETS>BuildSettings>Framework Search Pathsの値がそのプロジェクトのあるパスになっていればOKです。
※値としてはこのような変数が設定されていればOK→ "$(SRCROOT)"
※既に一度getting-startedの手順にてインストールしたことがある場合は、SDKへのパスが絶対パスで設定されてしまっていると思います。それは削除しちゃいましょう

あとはFacebookSDKのimportがエラーにならなければ、正しく読み込めていることになります。

これで、プロジェクトにFacebook SDKを同梱できました。
開発マシンとリリース作業をするマシンが別な時などはこの方法で対応しようと思います。

2012/09/24

iPhoneアプリからPOSTしたデータの確認

iPhoneアプリからサーバへ画像をPOSTする機能を実装しているとき、サーバサイド(今回はPHP)の出力(printやechoなんか)がXCode側で見られなかったので(俺がやり方をしらないだけ?)、サーバ側のテストプログラムでファイルを出力して確認してた。

一応インターフェースは決まっているが、名前ぐらいなので、POSTができない場合に問題を切り分ける必要があった。
つまり、アプリからはちゃんと送れてるぞという主張の根拠を提示したかったわけだw

ネットでvar_dump()をファイル出力する方法を見つけたので、$_REQUESTと$_FILESの情報をそのままvar_dump()してファイルに書き出してみた。拡張子が.htmlなのは、var_dump()して出力される内容がhtmlだったから。ブラウザからも確認しやすくてスゲー便利。var_dump()サイコー!

<?php

/**
 ■POSTサンプル
 
*/ if (isset($_FILES['file_data']['tmp_name'])) { // リクエスト情報 $filename = '_REQUEST.html'; ob_start(); echo "var:\n"; var_dump($_REQUEST); $out = ob_get_contents(); ob_end_clean(); file_put_contents($filename, $out); // ファイル情報 $filename = '_FILES.html'; ob_start(); echo "var:\n"; var_dump($_FILES); $out = ob_get_contents(); ob_end_clean(); file_put_contents($filename, $out); // ファイルを移動 copy($_FILES['file_data']['tmp_name'], getcwd( )."/".$_FILES['file_data']['name']); }
※うーむ。SyntaxHighlighterがおかしいなぁ。コードの後に謎の空行がたくさん…