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

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

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

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

8 голосов
/ 25 декабря 2011

Использование NSDictionary для передачи нескольких параметров является правильным способом сделать это в этом случае.

Однако, более современный метод заключается в использовании GCD и блоков, так что вы можете отправлять сообщения объекту.непосредственно.Кроме того, похоже, что ваш метод делегата может что-то обновлять в пользовательском интерфейсе;который вы правильно обрабатываете в главном потоке.С GCD вы можете сделать это легко и асинхронно, как это:

dispatch_async(dispatch_get_main_queue(), ^{
    [delegate imageWasLoaded:yourImage fromURL:yourString;
});

Замените ваш performSelector:withObject вызов этим, и вам не придется возиться с изменением сигнатур методов.

Убедитесь, что вы:

#import <dispatch/dispatch.h>

для поддержки GCD.

6 голосов
/ 26 декабря 2011

Поскольку у вас нет доступа к 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];
2 голосов
/ 25 декабря 2011

Также может использоваться следующий метод:

- (id)performSelector:(SEL)aSelector withObject:(id)anObject withObject:(id)anotherObject

Согласно документам этого метода - вызывает метод приемника в текущем потоке, используя режим по умолчанию после задержки.

1 голос
/ 25 декабря 2011

Да, у вас правильная идея: вам нужно инкапсулировать все данные, которые вы хотите передать делегату в основном потоке, в один отдельный объект, который передается через performSelectorOnMainThread.Вы можете передать его как NSDictionary объект, или NSArray объект, или как некоторый пользовательский объект Objective C.

...