ヘッダのカスタマイズや独自処理をしたいときの AFNetworking 2.0 の使い方

ヘッダのカスタマイズや独自処理をしたいときの AFNetworking 2.0 の使い方

普通の使い方

AFHTTPRequestOperationManager というクラスを主に利用します。 GETで通信したい場合は、以下のように GET:parameters:success:failure: メソッドを呼び出すことで、リクエストを開始することができます。 parameters: に NSDictionary 型のデータを渡せば、それをよしなにURIパラメータやBODYに付与してくれます。

サーバとの通信に成功しレスポンスが返って来た場合には、success: で指定したブロックが呼び出されます。また、ネットワークに繋がっていなかったり、指定したURLのサーバホストの名前解決がでいないなどサーバとの通信に失敗した場合は、failure: で指定したブロックが呼び出されます。 ちなみに、AFHTTPRequestOperation からステータスコードやレスポンスヘッダといった情報を取り出すことができます。

GET 以外には、POST, DELETE, PUT 用のメソッドも用意されています。

ヘッダのカスタマイズ

さて、ここからカスタマイズ編です。リクエスト時のヘッダをカスタマイズしたい場合は、以下のように AFHTTPRequestOperationManagerrequestSelializer というプロパティに対して、setValue:forHTTPHeaderField: を呼び出します。 NSMutableURLRequest にヘッダを設定する場合と似てますね。

ちなみに、BASIC認証したい場合は、以下のメソッドが使えます。

NSURLRequest のカスタマイズ

リクエストを開始する前にNSURLRequestにある処理を実行したいという場合があると思います。 例えば、Parse を使っていてリクエストヘッダにアクセストークンを付与したい場合、以下のように行うことができます。

最初に紹介したやり方よりは記述量が多くなってしまいますが、必ず毎回実行したい処理ならAFHTTPRequestOperationManagerのカテゴリ拡張もしくはサブクラスを作っても良いかもしれません。

Reference

  • http://qiita.com/asakahara/items/9cb68bef56ca70b505c6
  • http://qiita.com/jtemplej/items/c3c25a5301c7250305fe
    • Request Serialization, Response Serialization の説明がわかりやすい

NSSetの内部実装

NSSet の内部実装

ふと気になったので調べてみたところ、以下のリンクを見つけた。

どうやら実装としてはハッシュテーブルらしい。だから、要素の挿入、削除、検索が一定時間でできる。

なんでそんなことがわかるかというと、NSSet のC言語実装である CFSet が CFHashTable というハッシュテーブルを使って書かれているから。

実は CoreFoundation のソースコードは公開されていて、その一部である CFSet のソースコードも見ることができる。

CFSet のメソッドを見ていると、NSSet のどのメソッドと対応しているか、それとなくわかる。気になる実装を軽く眺めてみるだけでも楽しいかも。もしかしたら、CoreFoundation のクラスの内部でクラッシュした時に、参考になるかも(笑)

CoreDataのNSFetchedResultsControllerに関するメモ

NSFetchedResultsController の挙動について少しまとめます。
UITableView で CoreData のデータを利用するときに使うクラスです。

初期化

まず NSFetchedResultsController の初期化方法

  • fetchRequest
    • View に表示するためのデータを取得するための NSFetchRequest を指定
    • NSFetchRequest に NSSortDescriptor は必ず指定しないといけない
  • context
    • データの取得、変更の監視を行う NSManagedObjectContext を指定
  • sectionNameKeyPath
    • セクションを指定するときに指定する。
  • cacheName
    • fetch した結果をディスクにキャッシュするかどうか
    • キャッシュしない場合は、nil を指定

デリゲートメソッド

UITableView 上でのデータの挿入、更新、削除、移動イベントに対して、何か独自の処理を行いたいときは、NSFetchedResultsController にデリゲートをセットします。

NSFetchedResultsController のインスタンスに delegate を指定すると、以下のデリゲートメソッドが呼ばれる。

デリゲートメソッドの実装方法

以下がデリゲートメソッドの実装方法です。ほとんどAppleのサンプルコードと同じです。
NSFetchedResultsChangeUpdate の時だけちょっと実装を変えています(理由は こちら)。
例えば、新しいデータがインサートされてきた時に、ダウンロード処理をフックするとか、独自の処理をここに記述できます。

デリゲートメソッドが呼ばれるタイミング

controller:didChangeObject:atIndexPath:forChangeType:newIndexPath: が呼ばれるのは、初期化時に指定した context に変化があった時です。変化というのは以下の3種類。

  • NSFetchedResultsChangeInsert
    • [NSEntityDescription entityForName:inManagedObjectContext:] が実行された時
  • NSFetchedResultsChangeUpdate
    • NSManagedObject のインスタンスに値が代入された時
    • ※インスタンスが保持している値と代入する値が全く同じでも、デリゲートが呼ばれます
    • ※セルにアニメーションを仕込んでいるときは要注意(セルがリロードされて何度もアニメーションが発生してしまうので)
  • NSFetchedResultsChangeDelete
    • [NSManagedObjectContext deleteObject:] が実行された時

NSManagedObject の変化がまとめてこのデリゲートメソッドに通知されます(controllerWillChangeContent: と controllerDidChangeContent: が1回呼ばれる間に、 複数 controller:didChangeObject:atIndexPath:forChangeType:newIndexPath: が呼ばれる)。[NSManagedObjectContext save:] を呼び出した時に、NSManagedObjectContextDidSaveNotification の通知が飛ばされます。NSFetchedResultsController は内部的にこの通知を購読していて、この通知を受け取った時に、これらのデリゲートメソッドを呼び出しているのではないかと思います。

複数の変化がまとまってやってくるので、非同期処理とかここで行う場合は要注意です。
controller:didChangeObject:atIndexPath:forChangeType:newIndexPath: で渡ってくる indexPath のセルと非同期処理のコールバックで戻ってきた時に処理を行うセルがミスマッチしていて、適切に更新できない場合があります。

キャッシュ

キャッシュを使うかどうかは、NSFetchedResultsController の初期化時点で指定することができます。
キャッシュを使うことで、NSManagedObject と UITableView の indexPath の対応を再計算するコストを回避できます。キャッシュを利用する際の注意点について。私はこのキャッシュについてあまり理解せず使っていて、ちょっとハマりました。。

  • 複数の NSFetchedResultsController で同じキャッシュを利用していけない。キャッシュ名はしっかり分ける。
  • NSFetchRequest の predicate や sortDescriptors が変わった場合、fetchedResultsController を呼び出す前に、deleteCacheWithName: を呼び出して、キャッシュをクリアする必要がある。

NSFetchedResultsController v.s. NSFetchRequest

ただ単に CoreData からデータを取得したいだけなら、NSFetchedResultsController を使う必要はないです。
以下のように、NSFetchRequest を使うことで、クエリの実行が可能です。

リンク

iOS Core Data徹底入門
iOS Core Data徹底入門

posted with amazlet at 14.01.01
國居 貴浩
秀和システム
売り上げランキング: 12,185

iosのクリップボードの変化を検知するOSS「GLPasteboardMonitor」を公開しました

https://github.com/gologo13/GLPasteboardMonitor

iOS のクリップボード(UIPasteboard の generalPasteboard)の変化を検知し、通知が受け取れるようにするOSS「GLPasteboardMonitor」を公開しました。

使い方は github に書いてあるので、よかったら使ってみてください。 あまり大したことはしていないのですが、ポイントを上げるとすると、

  1. バックグラウンドでも変化を検知できるように、 Task Competion を使っている点
  2. 画像データの比較で、単純なバイト列の比較ではなく、ハッシュ値を元に比較し、比較を高速にしている点

です。

サンプルのプロジェクトでは、クリップボードの変化を検知すると、Local Notification を飛ばすようになってます。

dispatch_create_queueを使うときの勘違い

久々エントリ。

queue を作るとき、dispatch_create_queue の第1引数に名前を指定する。 ところが、すでに同じ名前の queue があるからといって、その queue が再利用されるわけではない

例えば、以下のコードはqueueの生成コストがすごく無駄

ドキュメントに書いてあるけど、このラベルは本質的に意味はなくて、デバッグ時の queue の識別子として使われるだけであった。

label

A string label to attach to the queue to uniquely identify it in debugging tools such as Instruments, sample, stackshots, and crash reports. Because applications, libraries, and frameworks can all create their own dispatch queues, a reverse-DNS naming style (com.example.myqueue) is recommended. This parameter is optional and can be NULL.

だから、上のソースコードは「1個のキューに対して、100個のタスクが直列に実行」されるわけではなく、「100個のキューに対して、1個のタスクが直列に実行」される。よって実質的には並列キューみたいにタスクが実行される。

参考