Хороший способ выполнить селектор в главном потоке с двумя параметрами?
Я ищу хороший способ выполнить селектор в главном потоке с двумя параметрами
Мне очень нравится использовать
- (void)performSelectorOnMainThread:(SEL)aSelector withObject:(id)arg waitUntilDone:(BOOL)wait
Метод, кроме теперь у меня есть два параметра.
Так что в основном у меня есть делегат, которого я должен уведомить, когда изображение загружается:
[delegate imageWasLoaded:(UIImage *)image fromURL:(NSString *)URLString;
Но метод, в котором я это делаю, может быть вызван в фоновом потоке, и делегат будет использовать это изображение для обновления пользовательского интерфейса, поэтому это необходимо сделать в основном потоке. Поэтому я действительно хочу, чтобы делегат также был уведомлен в основном потоке.
Итак, я вижу один вариант - я могу создать словарь, таким образом, у меня есть только один объект, который содержит два параметра, которые мне нужно передать.
NSDictionary *imageData = [NSDictionary dictionaryWithObjectsAndKeys:image, @"image", URLString, @"URLstring", nil];
[(NSObject *)delegate performSelectorOnMainThread:@selector(imageWasLoaded:) withObject: imageData waitUntilDone:NO];
Но такой подход мне не кажется правильным. Есть ли более элегантный способ сделать это? Возможно, используя NSInvocation? Заранее спасибо.
4 ответа
Поскольку у вас нет доступа к GCD, NSInvocation, вероятно, ваш лучший выбор здесь.
NSMethodSignature *sig = [delegate methodSignatureForSelector:selector];
NSInvocation *invoke = [NSInvocation invocationWithMethodSignature:sig];
[invoke setTarget:delegate]; // argument 0
[invoke setSelector:selector]; // argument 1
[invoke setArgument:&arg1 atIndex:2]; // arguments must be stored in variables
[invoke setArgument:&arg2 atIndex:3];
[invoke retainArguments];
/* since you're sending this object to another thread, you'll need to tell it
to retain the arguments you're passing along inside it (unless you pass
waitUntilDone:YES) since this thread's autorelease pool will likely reap them
before the main thread invokes the block */
[invoke performSelectorOnMainThread:@selector(invoke) withObject:nil waitUntilDone:NO];
В этом случае использование NSDictionary для передачи нескольких параметров является правильным способом.
Однако более современным методом является использование GCD и блоков, таким образом вы можете отправлять сообщения объекту напрямую. Кроме того, похоже, что ваш метод делегата может что-то обновлять в пользовательском интерфейсе; который вы правильно обрабатываете в главном потоке. С GCD вы можете сделать это легко и асинхронно, как это:
dispatch_async(dispatch_get_main_queue(), ^{
[delegate imageWasLoaded:yourImage fromURL:yourString;
});
Замените свой performSelector:withObject
позвоните с этим, и вам не придется возиться с изменением сигнатур методов.
Убедись, что ты:
#import <dispatch/dispatch.h>
внести в GCD поддержку.
Следующий метод также может быть использован:
- (id)performSelector:(SEL)aSelector withObject:(id)anObject withObject:(id)anotherObject
В соответствии с документами этого метода - вызывает метод приемника в текущем потоке, используя режим по умолчанию после задержки.
Да, у вас есть правильная идея: вам нужно инкапсулировать все данные, которые вы хотите передать делегату в главном потоке, в один отдельный объект, который передается через performSelectorOnMainThread
, Вы можете передать его как NSDictionary
объект или NSArray
объект, или некоторый пользовательский объект Objective C.