Xcode5でカバレッジをJenkinsに表示する
Qiita の Advent Calendar に投稿しました。
iOS - Xcode5でカバレッジをJenkinsに表示する
pod install でエラー
いつの頃からか、cocoaPodsで pod install すると下のようなエラーが出るようになっていました。
error: cannot open .git/FETCH_HEAD: Permission denied
以下のコマンドで解決しました。
sudo chown -R username ~/.cocoapods
それからこれも必要。
sudo chown -R username ~/Library/Caches/CocoaPods
KVOでNSMutableArrayを監視する
まずは、NSMutableArrayに対してKVOで監視するようにセットしてやります。
ViewController.m
- (void)viewDidLoad { [super viewDidLoad]; //FeedItemManagerクラスn items プロパティに変更があったらKVO発火 [[FeedItemManager sharedManager] addObserver:self forKeyPath:@"items" options:NSKeyValueObservingOptionNew context:nil]; } //これが発火するメソッド - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context{ if (object == [FeedItemManager sharedManager] && [keyPath isEqualToString:@"items"]) { //色々処理 } }
ところが、下のように値をかえても発火しません。
self.items = deedItems;
調べた結果、以下のように mutableArrayValueForKey でラップしてやると発火するようになりました。
[[self mutableArrayValueForKey:@"items"] insertObjects:items atIndexes:[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, items.count)]];
まわりくどいやり方ですね。。。
UITableVeiwのDataSourceとDelegate
皆さん、UITableViewのDelegate と DataSource ってどこに書かれてますか?
ViewController と別クラスとして実装されてる方もいらっしゃるとは思いますが
Delegate と DataSource を別々にされている方はあまりいないのではないでしょうか。
今回、2画面で同じテーブルビューを表示していて
DataSource だけ共通のものを使いたかったので DataSourceだけ
外出しして別クラスにしたんですが、そこでハマっていまいました。
セルの高さを変更するメソッド
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
これって、ずっとDataSourceだと思ってたのですが Delegate なんですね。。。
知らなかった。。。
ヘッダービューの変更とかもそうですね。
- (UIView*)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
2時間も無駄にしてしまった。。。
FMDB の kvcMagicメソッド
FMDBを使ってSQLiteをさわろうと思って色々と調べてたら次のメソッドを発見。
kvcMagic!!!
なんとも怪しげな名前ではないですか。
実はこのメソッド、 Cocoa の Key-Value Coding を利用して
SQL実行結果を、引数で渡したオブジェクトに突っ込んでくれるのです。
- (void)kvcMagic:(id)object { int columnCount = sqlite3_column_count([_statement statement]); int columnIdx = 0; for (columnIdx = 0; columnIdx < columnCount; columnIdx++) { const char *c = (const char *)sqlite3_column_text([_statement statement], columnIdx); // check for a null row if (c) { NSString *s = [NSString stringWithUTF8String:c]; [object setValue:s forKey:[NSString stringWithUTF8String:sqlite3_column_name([_statement statement], columnIdx)]]; } } }
なんて便利なんだと思ってたら、これデータ型が何であろうとすべて文字型 を突っ込んでいるではないですか。。。
というわけで、ここからHacking。
と思ってたら、すでにやってる人がいたので以下Gist。
kvcMagic: for more than just strings....
いやー、実に便利ですね。
これこそObjective-Cの真骨頂。
パラメータにEntityクラスを渡してやれば、すべてうまく行きそうですね。
ただ、Entityの@property を小文字で定義していたので、上のソースに lowercaseString を入れてやるとうまくいきました。
ARCでの @try -@catch
非ARC環境だと、@tryブロックで例外スローしたら
release が呼ばれないのでリークしてしまう。
なので 確実に実行される @finallyブロックで release する必要がある。
一方ARC環境ではどうかというと
まず release を書くとエラーになるので書けません。
ARCの場合であっても、コンパイラフラグに -fobjc-arc-exceptions を指定してやることで
例外処理のコードを生成してくれるようになります。
しかし、このコードサイズがかなり大きなものになってしまうらしく
実行時にパフォーマンスが下がってしまう。
なので結局は、Appleが推奨している通り、できる限りエラーの処理にはNSError を使うのがベストなのでしょうね。