多くのインスタンスを作成する小さな値クラスがあります。多くの場合、同じ値です。このクラスは一種の識別子として使用されるため、主な用途はこのクラスのインスタンスを相互に比較することです ( を介して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:
をより高速なポインター比較に置き換えることができるようにします。(はい、これを測定しました。これは重要です)。
シングルスレッドコードの場合、またはNSMutableSet
weakの代わりにを使用していた場合、NSHashTable
これは常に機能します。競合状態があるかどうかわからないので、次のような場合があります
[a isEqual: b] && (a != b)
本当です。