5

多くのインスタンスを作成する小さな値クラスがあります。多くの場合、同じ値です。このクラスは一種の識別子として使用されるため、主な用途はこのクラスのインスタンスを相互に比較することです ( を介してisEqual:)。

メモリと比較時間を節約するために、一意のインスタンスのみを a に保持し、 のNSHashTable代わりにポインター比較を使用しますisEqual:

したがって、指定された初期化子は次のようになります。

- initWithStuff: (NSString *)stuff;
{
    self = [super init];
    if (!self) return nil;

    // ... (actual initialisation code omitted)

   hash = UniquingHashTable();

   static OSSpinLock spinlock = OS_SPINLOCK_INIT;
   OSSpinLockLock( &spinlock );

   id member = [hash member: self];
   if (member) self = member;
   else [hash addObject: self];

   OSSpinLockUnlock( &spinlock );

   return self;
}

UniquingHashTable()グローバルを返すか、まだ存在しない場合NSHashTableは作成します。[NSHashTable weakObjectsHashTable]これweakObjectsHashTableは重要なビットです。そのオブジェクトへの強い参照が他になくなると、自動的に削除されるオブジェクトへの弱いポインターを格納します。のおかげで、初期化はスレッドセーフdispatch_onceです。

これは問題なく動作し、ピーク時のメモリ使用量は大幅に減少し、すべてのテスト ケースに合格しています。しかし、等しいかどうかをテストするためにポインター比較に頼ることができるかどうかはよくわかりません。同時に 2 つの異なるインスタンスを取得する (そのため、ポインターが異なる) ケースまたは競合状態はありますisEqual:か?

私が持っている/欲しいものを明確にするために:

与えられた

MyClass *a = [[MyClass alloc] initWithStuff: stringA];
MyClass *b = [[MyClass alloc] initWithStuff: stringB];

私たちはいつも持っています

[a isEqual: b] == [stringA isEqual: stringB];

これは、新しいコードでは変更されません。

私が達成しようとしているのは、それも

[a isEqual: b] == (a == b)

isEqual:をより高速なポインター比較に置き換えることができるようにします。(はい、これを測定しました。これは重要です)。

シングルスレッドコードの場合、またはNSMutableSetweakの代わりにを使用していた場合、NSHashTableこれは常に機能します。競合状態があるかどうかわからないので、次のような場合があります

[a isEqual: b] && (a != b)

本当です。

4

1 に答える 1