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 を使うのがベストなのでしょうね。