2013年度を振り返る

備忘録として、2013年度を振り返ってみたいと思う。

新しく挑戦したこととしては、iOSアプリ開発。昨年に入った頃からネイティブアプリ開発に興味を持ち始めて、個人的に Objective-C の勉強を始めた。主に参考にした本は 詳解 Objective-C 2.0 第3版iPhoneアプリ開発のコツとツボ35。仕事でも前のプロジェクトでiOSアプリ開発したいと手をあげたら、開発をやらせてもらえた。そして、今のプロジェクトではiOSチームのリーディングを担当するようになった。 ただ、まだプライベートでiOSアプリをリリースで来ていないので、今年はアプリをリリースさせたい!

他には、英語の勉強とか社内外への情報発信とかもやりたいこととして挙げていたけど、結局ほとんどできなかった。でも少しずつ改善できているのでよしとする。

技術面以外で痛感したことは、サービスを成長させることの難しさ。すごいエンジニアが何人もいるプロジェクトだからといって、生み出されたサービスが成功するとは限らない。当たり前なんだけど、実際に新規サービスを立ち上げてからサービスを運用することの難しさを実感できた1年だった。ユーザが全然使ってくれなくて、終了したサービスもある。 私はどれだけ頑張っても数字で結果を残せないなら、ビジネス上は「価値がない」と思ってる。だから、この1年は技術面だけでなく、サービスで結果が残せる1年にしたい。そのため、「リーン・スタートアップ」とか「グロースハック」という分野に興味を持ち始めている。本格的な勉強はできていないけど。。

プライベートでは、結婚という1つの大きなイベントがあった。ハネムーンでハワイにいってきた。ハネムーン以外ではあまり旅行に行けなかったので、もうちょっと仕事とプライベートのバランスを重視して過ごしたい。

そんな1年でした。

「iOSアプリ:テスト自動化入門」が届いた

すごく読みたかった本がようやく届いた。

バックエンド系のシステムだと自動テストがあるのは当たり前になってきたけど、まだまだネイティブアプリでは自動テストが書かれていないというのが実情だと思ってる(私もあまり出来ていない)。 テストができていないと、つまらないミスでアプリがクラッシュしてしまい、AppStoreのレビューが荒れて悲惨なことになる。。 かといって、リリース前に毎回手動テストするのもそれはそれでコストなので、そこでテストの自動化でしょという話になってくる。

既存のアプリのすべてのコンポーネントに自動テストを一気に用意するのは、大変だと思うけど、テストを書きやすいところから書いていければいいと思う。UIに依存しない部分、APIにリクエストして結果を取得する部分など。 現実問題、UIのテストってやるべきなのかって話もあるからね。

とりあえず目次を貼って終わりにします。

iOSアプリ テスト自動化入門|書籍情報|秀和システム

ヘッダのカスタマイズや独自処理をしたいときの 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 のクラスの内部でクラッシュした時に、参考になるかも(笑)

社内LTでCoreDataをバックグラウンドで扱うTipsについて話しました

社内で行われている iOS_LT に初参加してきました。
その時に発表した内容をシェアします。

PR枠として、最近リリースしたアプリについても宣伝しています(笑)
良かったらぜひダウンロードをお願いします!→こちらから

5分という発表時間だったので、CoreData で使うクラス(NSManagedObjectContext, NSManagedObject)の説明とかは省略しています。
話せなかった内容としては、Nested Context, 永続化ですね。
ここらへんはまた別の機会に話せればと思います。

WordPressに全件表示のアーカイブを作る方法(はてブ数表示付き)

この WordPress で作ったブログにアーカイブを作ってみました。

archive

設置方法

アーカイブ表示用のPHPスクリプトを設置する方法については WordPressで過去記事一覧(アーカイブ)を作成する を御覧ください。

全く同じだと芸がないので、別方法でアーカイブを実装してみました。wp_get_archives という WordPress にアーカイブ取得専用の関数があるのですが、カスタマイズ性に乏しいためです。

今回の実装では、アーカイブに「日付+タイトル+はてブ数」を表示してみました。

実装で、query_posts()というブログエントリを取得する関数を使用しました。引数に showposts を指定することで取得するエントリ数を制御できます。私の場合、全件取得したかったので、query_posts('showposts=-1') としました。

PHP Script

Link

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個のタスクが直列に実行」される。よって実質的には並列キューみたいにタスクが実行される。

参考

iOS Developer Progamで複数チームに所属することは可能か?

iOS Developer Progamで複数チームに所属することは可能か?

結論としては、可能です。

添付したスクリーンショットのように、iOS dev center にログインするたびに、どのチームで操作を行うかを選択することができる。

すでにあるチームの Developer Program に所属している状態で、新規で Developer Program に参加しようとした時、

  • 古いチームの情報が上書きされてしまい、無効になる
  • 既にチームに参加しているから、新規で参加できない

と、懸念があったが、全くそんなことはなかった。

個人的に安心できたので、シェアします。


以下、実機インストールまでの簡単な導入手順

  1. Safari で iOS Dev Center を開く(Chrome だとうまく行かないことがあった)
  2. デバイス登録:実機インストールするデバイス名, UDID(Xcode Identifier で調べられる)を登録
  3. AppID 登録:アプリのユニークなIDの作成
  4. 証明書登録:KeyChain Access で作成できる
  5. プロビジョニングプロファイル作成:実機インストールするための準備ファイル

詳しくは、ここ が参考になりそう。