Hatena::Groupiphone-dev

iOS プログラミングメモ

2013-08-22 (Thu)

[] Reachabilityが更新されてました 12:17  Reachabilityが更新されてました - iOS プログラミングメモ を含むブックマーク

Reachabilityといえば、ネットワークアクセス状況を監視するためにとりあえず使っとけというサンプルコードですが、実に3年ぶりにARC対応としてアップデートされてたので見てみました。

どうやらNDAな新しいXcodeでビルドしてあるらしくて、Xcode4.6.3だとビルドできません*1。なんということでしょうw そしてXcode4.6.3でビルドするにもMainStoryboardが開けない問題が解決できなくてダメでした。Document Versioning辺りをゴニョゴニョすればいいのかと思ったけど、それだけじゃうまくいきませんでした。Storyboardファイルを開こうとするとクラッシュする。うは。

まあ単純なUIなので、動作テストをするために適当にMainStoryboardを作りなおして試してみました。UIImageViewとUITextFieldとUILabelをいくつか置いて、APLViewControllerとOutletで接続するだけの簡単なお仕事です。これ以外にもSystemConfiguration.frameworkも追加しておおかないといけないので忘れずに。

今回のサンプルのページには「Runtime Requirements: iOS 6.0 or later.」となっていましたが、iOS5でもネットワークの状態の変化を検知できました。

さて、手元にReachabilityのバージョン2.2があるので、新しいバージョン3.0と見比べてみます。ヘッダファイルのクラスメソッドの返り値が全部instancetypeになっていますね。最近自分もよくやってます。

あとは変数名retValがreturnValueになっていたり、スペースの使い方が変わってたり、コメントが//〜から/*〜*/に変わってたりどうでもいい変更ばっかりでした。ARC対応もautoreleaseとAutoreleasePoolを消したくらい。

*1:ちなみにサンプルコード自体はログインしなくても見れるので、NDA範囲外でしょう

appleapple2014/01/21 16:1571をコピペまるまるしたんですが#import "VoiceSwitch.h"ここの部分でファイルノットファウンドがでるんですが、どうすればよろしいですか?

ktakayamaktakayama2014/01/23 16:56すいません、Reachabilityのことではないですよね…。
ちょっとよくわからないのですが、VoiceSwitch.hというファイルがプロジェクトに入ってないのではないでしょうか?

トラックバック - http://iphone-dev.g.hatena.ne.jp/ktakayama/20130822

2013-08-09 (Fri)

[] NSStringの文字列比較はisEqualToStringではなくてcompareメソッドがいいのか 16:52  NSStringの文字列比較はisEqualToStringではなくてcompareメソッドがいいのか - iOS プログラミングメモ を含むブックマーク

Appleのサンプルコード DownloadFont を眺めてたら、NSStringの文字列比較にcompare:メソッドを使っていて「あれisEqualToStringじゃないの?」って思ったので調べてみたら意外と重大な事実が判明しました。isEqualToStringはNSLiteralSearchオプションによる比較なので、見かけ上同じ文字列だったとしてもバイト列が異なる場合はNOを返すらしい。うはー、こんな基本的なことを知らなかったとか恥ずかしいです。

たとえば以下のコードの場合ですとisEqualToStringは通りませんが、compare:はNSOrderedSameを返すので真になります。

NSString *stringA = @"\343\203\221\343\202\272\343\203\211\343\203\251";
NSString *stringB = @"\343\203\217\343\202\232\343\202\271\343\202\231\343\203\210\343\202\231\343\203\251";

if([stringA isEqualToString:stringB]) NSLog(@"isEqualToString");
if([stringA compare:stringB] == NSOrderedSame) NSLog(@"compare");

stringAが「パズドラ」という文字で、stringBは濁点と半濁点が分離した文字になっています。Macのファイルシステムで使われてる UTF-8-MAC がこの分離文字を扱ってるので、結構おなじみかもしれません。

そういえば拙作の SkyBook でも、内蔵ストレージに保存した濁点付きの文字列の比較がうまくいかなくて困った経験がありました。その時は分離した文字列をくっつけるように変換して対処しましたが、compare:使うのが正解だったのか!!

参考までにSkyBookでやったやり方はこちら。

NSString *stringA = @"\343\203\221\343\202\272\343\203\211\343\203\251";
NSString *stringB = @"\343\203\217\343\202\232\343\202\271\343\202\231\343\203\210\343\202\231\343\203\251";

NSMutableString *stringC = [NSMutableString stringWithString:stringB];
CFStringNormalize((CFMutableStringRef)stringC, kCFStringNormalizationFormC);

if([stringA isEqualToString:stringC]) NSLog(@"great!!");

これだとgreat!!と出力されます。

2013-05-28 (Tue)

[] MapSearch 15:31  MapSearch - iOS プログラミングメモ を含むブックマーク

せめて一週間に一回くらいは勉強を兼ねてサンプルコード読んで感想を書いて人気ブログになってアフィリエイトでウハウハとか思ってたのに、もう一ヶ月も間が空いてしまった。そんなバカな。てかここにアフィリエイトなかったかも。

というわけで今日は MapSearch です。5月17日にアップロードされたサンプル。

iOS6.1から MKLocalSearch ていうクラスが追加されて住所とか地名とかの情報を使って地図の検索ができるようになったっていうサンプルみたい。そうかそうか、そういえば以前は検索なんてできなかったのか。

f:id:ktakayama:20130528154420p:image:w200 f:id:ktakayama:20130528154414p:image:w200

coffee って入力すると coffee 店が見つかるらしいけど、そういうのは日本の地図では対応していないらしくてなんもひっかからない。寂しい。こういうの POI っていうらしくて木下さんが紹介していた。

さて難しいことは置いといて、MapSearch のコードを読んでみるのが目的なので読もう読もう。…さっそく画面遷移に関して疑問が。UIStoryBoardSegue を継承したクラスを作って、そのインスタンスを作ってから perform 実行してるんだけど、なんでだろうか。テーブルの画面ですでに MapViewController のインスタンスを生成して保持してるからっぽいなあ。地図は読み込み遅そうだから使いまわしたかったのかな。確かにこのアプリの場合は2つの画面を行ったり来たりするだけだから、なんども初期化するのは無駄だしいいかも。細かい所だけど凝ってる。

↓ のコード。viewDidLoad 内で DetailSegue (UIStoryBoardSegueを継承したクラス)のインスタンスを作って、tableView didSelectRowAtIndexPath の時に呼び出してる部分のこと。

検索の部分はシンプルでわかりやすかった。検索するんだったら、このコードそのまま使うといいんじゃないかなあ。基本的に - (void)startSearch:(NSString *)searchString; の中で完結してそう。

MapViewController の方は単にリストで保持された MKMapItem にポコポコとピンを立ててるだけで特に思うところはなかった。

終わり。

ちなみに、サンプルコードは以下の RSS で最新情報をチェックしてます。

トラックバック - http://iphone-dev.g.hatena.ne.jp/ktakayama/20130528

2013-04-27 (Sat)

[] StateRestore 21:41  StateRestore - iOS プログラミングメモ を含むブックマーク

iOS4 からアプリを終了してもしばらくの間は状態がそのままで次に起動した時は終了時の状態が復元するけど、メモリが少なくなった時とかは必ずしも復元するわけじゃないから、そんな場合にも手軽に状態を復元できるようにするための便利機能が iOS6 で搭載されたというわけで、そのサンプルが StateRestore でした。

Storyboard 上でそれぞれの ViewController に Storyboard ID と Restration ID を指定しておいてから、AppDelegate と ViewController 上で状態の保存・復元用のコードを書くだけでいいと。Info.plist で Application does not run in background (UIApplicationExitsOnSuspend) を YES にすると動きがわかりやすくていいかも。modal を開いてテキストを適当に入力した状態でアプリを終了しても、完璧に復元する。

テーブルの状態管理が少しややこしそうかなあ。モデルの識別子を保存して、復元させる時はその識別子を使って indexPath を得るということをしてるようだ。

- (NSString *) modelIdentifierForElementAtIndexPath:(NSIndexPath *)idx inView:(UIView *)view
- (NSIndexPath *) indexPathForElementWithModelIdentifier:(NSString *)identifier inView:(UIView *)view

Prefix.pch に書いてある MANUALLY_CREATE_VC_FOR_RESTORATION ていうマクロを有効にすると、状態復元時の ViewController の生成処理のサンプルコード(下に書いた長ったらしい名前のメソッドの実行サンプル)が有効になるみたい。

+ (UIViewController *) viewControllerWithRestorationIdentifierPath:(NSArray *)identifierComponents  coder:(NSCoder *)coder

この viewControllerWithRestorationIdentifierPath は必ずしも使う必要はないわけだけど、たとえばロード済みの Controller を返したりとかそういう感じで使うっぽいとかドキュメントに書いてあるっぽいんだけどよくわからん。

DataSource クラスと Item クラスが超シンプルなデータモデルになってて NSKeyedArchiver で永続化しているので、この辺やったことない人は参考になるかも。

トラックバック - http://iphone-dev.g.hatena.ne.jp/ktakayama/20130427

2013-04-21 (Sun)

[] TheElements 23:42  TheElements - iOS プログラミングメモ を含むブックマーク

Appleのサンプルコード見て勉強してます。今回は元素の情報を表示する TheElements から。

このサンプルで使ってるテクニックというのが Readme に書いてあるんだけど、結構盛りだくさん。

Configuring and responding to selections in a tab bar

Displaying information in a tableview using both plain and grouped style table views

Using navigation controllers to navigate deeper into a data structure

Subclassing UIView

Providing a custom UITableViewCell consisting of multiple subviews

Implementing the UITableViewDelegate protocol

Implementing the UITableViewDataSource protocol

Reacting to taps in views

Open a URL to an external web site using Safari

Flipping view content from front to back Creating a reflection of a view in the interface

https://developer.apple.com/library/ios/#samplecode/TheElements/Listings/Readme_txt.html

アプリの構成はシンプルで、UITabViewController の中に4つの UITableViewController があってそれぞれのテーブルは元素のリストがさまざまな条件で並んでいる。

f:id:ktakayama:20130421232308p:image:w200

コードの方でまず最初に目についたのが、AppDelegate で UITabBarController を作ってるところ。UIの基本的な部分は StoryBoard で作られてるんだけど、StoryBoard はかなりシンプルで画面遷移くらいしか表現されていない。UITabBarController > UINavigationController > UITableViewController > UIViewController みたいな。UITabBarController の中も1個のタブしかないし。どうなってんのかと思ったら、AppDelegate で UITableViewController のインスタンスを4回生成してた。こんな風に使いまわしたことはなかったから新鮮だった。

// by name
UINavigationController *navController = [storyboard instantiateViewControllerWithIdentifier:@"navForTableView"];
ElementsTableViewController *viewController =
  (ElementsTableViewController *)[navController topViewController];
dataSource = [[ElementsSortedByNameDataSource alloc] init];
viewController.dataSource = dataSource;
[viewControllers addObject:navController];

// by atomic number
navController = [storyboard instantiateViewControllerWithIdentifier:@"navForTableView"];
viewController = (ElementsTableViewController *)[navController topViewController];
dataSource = [[ElementsSortedByAtomicNumberDataSource alloc] init];
viewController.dataSource = dataSource;
[viewControllers addObject:navController];

…以下続く

tabBarController.viewControllers = viewControllers;

UITableViewController で使うための dataSource がそれぞれ独立したクラスになってて、共通のインターフェイスが ElementsDataSource っていうプロトコルで定義されてる。こういうの自分の場合は親クラス作っちゃったりしてて、こんな感じにプロトコル扱えてなかったなあ。

カスタマイズした UITableViewCell を継承した AtomicElementTableViewCell 内にある要素は viewWithTag で取得するようになってた。これは良くやるね。IBOutlet でつなげることも多い。

AtomicElementView に reflectedImageRepresentationWithHeight: ていうメソッドがあって、View の内容を鏡のように上下反転させた UIImage を返してくれる。Music アプリのカバーフローと同じやつ。

f:id:ktakayama:20130421232310p:image:w200

その他に気付いたことメモ

  • UI の初期化は setupUserInterface ていう名前のメソッド内に書いてあった (AtomicElementFlippedView)
  • property 指定した時に自動でやってくれる setter を上書きするのってなんか怖かったんだけど、結構シンプルな書き方でいいんだなあとか (AtomicElementTableViewCell)
トラックバック - http://iphone-dev.g.hatena.ne.jp/ktakayama/20130421