1

私のコード (特にTDDに慣れるにつれて) には、次のような遅延ロードされたプロパティがたくさんあります。

@interface MyClass ()

@property (nonatomic, strong) MyFoo *myFoo;

@end

@implementation MyClass

- (MyFoo *)myFoo {
   if (!_myFoo) {
     _myFoo = [MyFoo alloc] sharedFoo]; // or initWithBar:CONST_DEF_BAR or whatever
   }
   return _myFoo;
}

@end

または、より良い、スレッドセーフなバージョン:

- (MyFoo *)myFoo {
  static dispatch_once_t onceToken;
  dispatch_once(&onceToken, ^{
    _storeHelper = [SHStoreHelper sharedStoreHelper];
  });
}

次のように、Apple がそれをプロパティの一部として自動コード生成の対象にしてくれたらいいのにと思います。

@property (lazyload) MyFoo *myFoo;

ただし、それを除けば、次のような実装ビットのマクロが必要です。

#define LAZY_ALLOC(x, y, _y, a, i) -(x *)y { if (!_y) { _y = [[x a] i]; } return _y }

そして、通常のメソッド実装の代わりに

LAZY_ALLOC(MyClass, myClass, _myClass, alloc, init)

必要なクラスに十分な柔軟性があります

LAZY_ALLOC(OtherClass, otherClass, _otherClass, sharedClass, nil)

また

LAZY_ALLOC(OtherClass, otherClass, _otherClass, alloc, initWithFrame:SOME_FRAME)

1) プリプロセッサには _y が必要です。_autosynthesized ivar を個別に渡さずに構築する方法はありますか? 2) これには大きな問題がありますか? 私にとっては、完全に書き出されたバージョンよりも本質的に「ああ、もう一度」と言うので、読みやすさが向上します 3) スタイル的に厄介だと思いますか? スタイル的に素晴らしい?

4

2 に答える 2

3

あなたが欲しいのは だと思います##。次のように記述できます。

#define LAZY_ALLOC(type, name, initialValue) \
    -(type *)name { \
        static dispatch_once_t onceToken; \
        dispatch_once(&onceToken, ^{ \
            if (! _ ## name) { \
                _ ## name = (initialValue); \
            } \
        } \
        return _ ## name; \
    }

編集:

明確にするために、私はこの特定のイディオムを、シングルトンのsharedInstance型メソッド以外の遅延読み込みには使用しません。このコードは、静的な dispatch_once_t のため、(インスタンスごとではなく)クラスごとに 1回だけ遅延読み込みを行います。問題からコードをコピーし、そのテクニックを説明するためにマクロ テンプレートに変換しただけですが、これを明確にする必要があるように感じます。

個人的には、通常のインスタンス変数を遅延ロードする場合は、スレッドセーフでないバージョンを使用し、スレッドセーフが必要な場合は熱心なロードに切り替えるか、ケースを特別に処理します。アクセサーで遅延読み込みとスレッド セーフを組み合わせる手法はいくつかありますが、次のような方法があります。

  1. それらはかなり遅いです。

  2. 両方が同時に必要になることはめったにありません。

  3. とにかく、アクセサーメソッドにミューテックスを貼り付けるだけでなく、スレッドセーフのために特別な設計を行う必要があるでしょう。

そのため、そのケースを標準のテンプレート マクロに組み込むことはしません。

于 2012-12-17T22:44:52.553 に答える
0

+(id) lazyLoad:(Class)class sharedPointer:(NSObject**)ptrAddrメソッドなどを書きます。このメソッドのみを実装する LazyLoader クラスのメソッドにします。

使用するには:

- (MyFoo *)myFoo {
    return [LazyLoader lazyLoad:[MyFoo class] sharedPointer:&_myFoo];
}

おそらく sharedPointer parm にいくつかの ARC スイートナーが必要ですが、基本的には動作するはずであり、(必要に応じて) 必要に応じてスレッドセーフにすることもできます。

(代わりの init メソッドを実行する方法を読者が理解するための演習として残しておきます。)

于 2012-12-17T22:40:14.700 に答える