読者です 読者をやめる 読者になる 読者になる

kanetaiの二次記憶装置

プログラミングに関するやってみた、調べた系のものをQitaに移して、それ以外をはてブでやる運用にしようと思います。http://qiita.com/kanetai

Effective Objective-C 2.0 第4章(プロトコルとカテゴリ)

項目23 オブジェクト間通信には、DelegateとDataSourceプロトコルを使う

@class myClass;
@protocol myDelegate <NSObject>
@optional
- (void)optionalMethod1:(myClass*)test;
- (void)optionalMethod2:(myClass*)test;
@end
@interface myClass : NSObject
- (void)doSomethingWithDelegate:(id<myDelegate>)delegate;
@end
  • デリゲートを持つクラスのプロパティは通常所有関係にならないのでweak属性となることが多い
  • optionalなデリゲートメソッドが頻繁に呼ばれる場合は、delegateのセッターでメソッドが実装されているかをビットフィールドでキャッシュしとくといい
#import "myClass.h"
@interface myClass () {
    struct {
        unsigned int optionalMethod1 : 1;
        unsigned int optionalMethod2 : 1;
    } _delegateFlags;
}
@property (nonatomic, weak) id<myDelegate> delegate;
@end
@implementation myClass
- (void)setDelegate:(id<myDelegate>)delegate {
    _delegate = delegate;
    _delegateFlags.optionalMethod1 = [delegate respondsToSelector:@selector(optionalMethod1:)];
    _delegateFlags.optionalMethod2 = [delegate respondsToSelector:@selector(optionalMethod2:)];
}
- (void)doSomethingWithDelegate:(id<myDelegate>)delegate {
    self.delegate = delegate;
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        //dosomething...
        if (_delegateFlags.optionalMethod1) {
            [_delegate optionalMethod1:self];
        }
    });
}
@end
- (void)optionalMethod1:(myClass *)test {
    if (test == self.instance1) {
        NSLog(@"optionalMethod1:instance1");
    } else if (test == self.instance2) {
        NSLog(@"optionalMethod1:instance2");
    }
}

項目24 カテゴリを使ってクラスの実装を管理できるサイズに分割せよ

  • カテゴリでクラスを分割実装できる。
  • 非公開のメソッドを分割したカテゴリで使いたい場合は、Privateというカテゴリを作ってそのヘッダをインポートする。そのヘッダは非公開とする。

項目25 サードパーティクラスに追加するカテゴリで使う名前には必ずプレフィックスを付ける

  • 自分のものでないクラスに追加するカテゴリの名前、カテゴリメソッドにはプレフィックスをつけようず

同じ名前のメソッドが追加されていると、どの実装が呼び出されるか分からなくなるから、無意識にオーバーライドしないようにするためにプレフィックスを付ける。

項目26 カテゴリではプロパティを使わないようにする

  • カプセル化されたデータのためのプロパティ宣言は、全てメインインターフェース定義に集める
  • カテゴリではプロパティ宣言ではなくメソッドを使う(クラス拡張(無名)カテゴリを除く)

カテゴリでプロパティ宣言をしても、インスタンス変数の自動合成できないので、@dynamicやassociated Objectを使う必要がある。

基本的にはメインインターフェース定義、無名カテゴリにプロパティ宣言を集めた方が良い。

項目27 実装の詳細を隠すためにクラス延長カテゴリを活用せよ

  • 非公開メソッドドキュメンテーションに使える
  • 実装でC++クラスを使う場合便利(ヘッダにC++の要素があれば、そのヘッダをインポートするファイルはObjective-C++として扱わないといけない)
  • 非公開のプロパティ、プロトコル準拠は無名カテゴリで宣言すると良い。ゲッタだけ公開したい場合は、ヘッダでreadonlyにしておいて無名カテゴリでreadwriteにすることもできる。

クラス延長(無名)カテゴリ

  • 通常のカテゴリとは異なり、拡張しようとしているクラスの実装ファイルで定義しなければならない
  • 通常どおり@propertyインスタンス変数の自動合成が行われる
  • ヘッダでreadonlyになっているプロパティをreadwriteにできる

項目28 プロトコルを使って無名オブジェクトを提供せよ

id<xxx>ってやつです。具体的なクラス名(型)を隠せる。そんだけ。