@syntheized(self) ロックをこのメソッドで置き換えていました
void _ThreadsafeInit(Class theClassToInit, void *volatile *theVariableItLivesIn, void(^InitBlock)(void))
{
//this is what super does :X
struct objc_super mySuper = {
.receiver = (id)theClassToInit,
.super_class = class_getSuperclass(theClassToInit)
};
id (*objc_superAllocTyped)(struct objc_super *, SEL, NSZone *) = (void *)&objc_msgSendSuper;
// id (*objc_superAllocTyped)(id objc_super, SEL, NSZone *) = (void *)&objc_msgSend;
do {
id temp = [(*objc_superAllocTyped)(&mySuper /*theClassToInit*/, @selector(allocWithZone:), NULL) init];//get superclass in case alloc is blocked in this class;
if(OSAtomicCompareAndSwapPtrBarrier(0x0, temp, theVariableItLivesIn)) { //atomic operation forces synchronization
if( InitBlock != NULL ) {
InitBlock(); //only the thread that succesfully set sharedInstance pointer gets here
}
break;
}
else
{
[temp release]; //any thread that fails to set sharedInstance needs to clean up after itself
}
} while (*theVariableItLivesIn == NULL);
}
これはもう少し冗長ですが、競合しないケースではパフォーマンスが大幅に向上します
この小さなマクロと一緒に (形式が悪いのは許してください。これは非常に単純です)。最初の nil チェックの後にブロックを宣言できるようにするために、LLVM が「既に初期化された」パスを非常に高速に保つのに役立つように見えます。それは私が気にする唯一のものです。
#define ThreadsafeFastInit(theClassToInit, theVariableToStoreItIn, aVoidBlockToRunAfterInit) if( theVariableToStoreItIn == nil) { _ThreadsafeInitWithBlock(theClassToInit, (void *)&theVariableToStoreItIn, aVoidBlockToRunAfterInit); }
そのため、最初は objc_superAllocTyped のコメントアウトされたセクションを使用して実装しました (実際には最初に [theClassToInit allocWithZone:NULL] を使用しましたが、これは間違いなく最良のアプローチでした:) )、プロジェクト内のほとんどのシングルトンが allocWithZone をオーバーライドしてシングルトンメソッドを返します...無限ループ。したがって、objc_msgSendSuper を使用するとすぐに解決できるはずですが、このエラーが発生します。
[51431:17c03] +[DataUtils allocWithZone:]: unrecognized selector sent to class 0x4f9584
エラーは実際の問題に関連していないようです...
(lldb) po 0x4f9584
$1 = 5215620 DataUtils
(lldb) print (BOOL)[$1 respondsToSelector:@selector(allocWithZone:)]
(BOOL) $2 = YES
だから私は間違いなく何かが欠けています...空のクラスの[super allocWithZone:NULL]メソッドによって生成されたアセンブリと比較しました...呼び出された関数の名前が異なることを除いてほぼ同じです(おそらく異なるシンボルを使用しているだけで、わかりませんよく読めない)。
何か案は?スーパークラスで class_getClassMethod を使用して IMP を直接呼び出すことができますが、ランタイムの悪用を合理的にしようとしています :)