Хороший способ выполнить селектор в главном потоке с двумя параметрами?

Я ищу хороший способ выполнить селектор в главном потоке с двумя параметрами

Мне очень нравится использовать

- (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.

Другие вопросы по тегам