2013-11-30 4 views
0

Метод swizzling используется в следующем синтаксическом инициализаторе, но я не уверен в безопасности потоков для swizzling.Thread-safety метода swizzling

Что происходит, когда поток собирается вызвать метод, который должен быть опробован другим методом? Безопасно ли вы в любой момент подпрыгивать, а есть потоки, чтобы вызвать этот метод? Ответьте на официальные ссылки, пожалуйста. Благодаря

#import <dispatch/dispatch.h> 
#import <objc/runtime.h> 

@implementation MySingleton 

static MySingleton * __singleton = nil; 

+ (MySingleton *) sharedInstance_accessor 
{ 
    return (__singleton); 
} 

+ (MySingleton *) sharedInstance 
{ 
    static dispatch_once_t __once = 0; 

    dispatch_once(&__once, ^{ 
       __singleton = [[self alloc] init]; 
     Method plainMethod = class_getInstanceMethod(self, @selector(sharedInstance)); 
     Method accessorMethod = class_getInstanceMethod(self, @selector(sharedInstance_accessor)); 
     method_exchangeImplementations(plainMethod, accessorMethod); 
     }); 
    return (__singleton); 
} 

@end 

https://gist.github.com/MSch/943369

+1

Что это точка этого кода? dispatch_once практически не наносит накладных расходов. На самом деле больно пари, чтобы быстрее проверить токен на дюжину (вероятно, еще больше) раз, чем это делать, чтобы сделать это swizzling. код тоже сложнее. –

+2

«Ответ на официальные ссылки пожалуйста» звучит так, как будто вы хотите, чтобы кто-то искал документы для вас ... – Dave

+1

Я отправил ответ, но должен сказать, что я не понимаю, чего вы пытаетесь выполнить, и почему вам нужно swizzling, чтобы сделать это. Объяснение этого поможет прояснить ваш вопрос. –

ответ

1

Согласно documentation, method_exchangeImplementations() атомарный. Предположительно, это означает, что если один из двух методов, которыми обмениваются, вызывается из другого потока одновременно с запуском method_exchangeImplementations(), он может получить предыдущий (необменяемый) метод, но он не получит что-то непоследовательное (например, выиграл 't crash).

Обратите внимание, что dispatch_once() является потокобезопасным, а также означает, что до тех пор, пока все ссылки на экземпляр singleton получаются с помощью +sharedInstance, ни один поток не будет ссылаться на объект до завершения swizzling.

Наконец-то, я обычно не хочу добавлять такие ответы к ответам, потому что понимаю, что иногда допросы просто пытаются узнать больше о том, как все работает, а не пытаться написать производственный код. Однако, если вы планируете использовать это в реальном, отправляющем коде, вы должны пересмотреть его. Swizzling имеет тенденцию быть «плохим запахом кода», и вполне вероятно, что есть лучший способ сделать то, что вы пытаетесь выполнить (что до сих пор неясно мне).

+0

'dispatch_once()' также также безопасен потоком. –

+0

@BradAllred, да, я изначально заметил, что в моем ответе, но его код недостаточно ясен, и я не был уверен, применил ли он его. Я отредактирую, чтобы добавить его обратно с оговоркой. –

2

Я сомневаюсь, что есть официальная ссылка на это, но нет необходимости.

Во-первых, исполняемый код метода не выводится из памяти. Таким образом, не имеет значения, какая реализация установлена, предыдущая реализация все еще доступна для выполнения.

Это означает, однако, что вы должны убедиться, что ваше управление данными является потокобезопасным (это значит, что никто не пытается напрямую позвонить sharedInstance_accessor).

Так что возникает вопрос, является ли method_exchangeImplementations() потокобезопасным. The source говорит, что это (и это не было несколько основных релизов ранее), а также документация.

Как сказал Брэд Оллред, это вряд ли будет стоить преследования.

+0

method_exchangeImplementations() является атомарным по документам, но это не то, что я ищу. он необходим для параллельных методов swizzles, которые не ожидаются в этом пользовательском классе. то, что я ищу, - это безопасность потоков между вызовом метода и методом swizzle. Я думаю, runtimeLock (http: // www.opensource.apple.com/source/objc4/objc4-551.1/runtime/objc-runtime-new.mm) достигает этого. – lockedscope

+0

objc_msgSend (http://www.opensource.apple.com/source/objc4/objc4-551.1/runtime/Messengers.subproj/objc-msg-x86_64.s) вызывает lookupMethodAndLoadCache3, который также использует runtimeLock. setImplementation также использует этот sync obj (runtimeLock), поэтому setImplementation сама по себе является потокобезопасной наряду с вызовом метода. – lockedscope

+0

Я бы порекомендовал решительно против того, чтобы спрятать блокировки времени выполнения. Вы обязательно обнаружите множество способов взаимоблокировки. – bbum

Смежные вопросы