Передача примитивов через performSelectorOnMainThread

хорошо, скажем, у меня есть второй поток, но он хочет манипулировать чем-то в основном потоке, например UI товар.

-(void)backgroundThread
{
    [myButton performSelectorOnMainThread:@selector(setEnabled:) withObject:(BOOL)YES waitUntilDone:YES];
     // right here, how could i pass this BOOL to the function
}

Я пробовал использовать NSNumber ' s numberWithBOOL, а NSButton не принимает его.

3 ответов


вы не можете использовать performSelectorOnMainThread:withObject:waitUntilDone: С аргументом, который не является объектом Objective-C, и вы не можете использовать NSNumber потому что нет автоматической распаковки от объектов к примитивным типам.

одним из решений является реализация аналогичного метода, который принимает кнопку в качестве аргумента и вместо этого вызывает этот метод.

например, в том же классе:

- (void)enableButton:(NSButton *)button {
    [button setEnabled:YES];
}

и

-(void)backgroundThread{
    [self performSelectorOnMainThread:@selector(enableButton:)
                           withObject:myButton
                        waitUntilDone:YES];
}

другое решение-реализовать категорию на NSButton С альтернативный метод (например,-setEnabledWithNumber:), и вместо этого используйте этот метод:

@interface NSButton (MyButtonCategory)
- (void)setEnabledWithNumber:(NSNumber *)enabled;
@end

@implementation NSButton (MyButtonCategory)
- (void)setEnabledWithNumber:(NSNumber *)enabled {
    [self setEnabled:[enabled boolValue]];
}
@end

и

-(void)backgroundThread{
    [myButton performSelectorOnMainThread:@selector(setEnabledWithNumber:)
                               withObject:[NSNumber numberWithBool:YES]
                            waitUntilDone:YES];
}

вы можете использовать блоки:

BOOL boolValue = YES;

[self performOnMainThreadWait:YES block:^(id owner) {
    [button setEnabled:boolValue];
}];

Это использует мою реализацию отложенных блоков:

@implementation NSObject (HHBlockPerform)

- (void)performAfterDelay:(NSTimeInterval)delay block:(HHPerformBlock)block
{
    [self performSelector:@selector(runBlock:) withObject:[block copy] afterDelay:delay];
}

- (void)performOnMainThreadWait:(BOOL)wait block:(HHPerformBlock)block
{
    [self performSelectorOnMainThread:@selector(runBlock:)
                           withObject:[block copy]
                        waitUntilDone:wait
                                modes:[NSArray arrayWithObject:NSRunLoopCommonModes]];
}

- (void)runBlock:(HHPerformBlock)block
{
    block(self);

    [block release];
}

@end

Да performSelectorOnMainThread:withObject:waitUntilDone: больше не работает с примитивными типами. В прошлом это работало, пока у вас был только один аргумент, и это был интегральный тип, который можно было без потерь преобразовать из/в указатель. Это было небезопасно и некрасиво, но сработало.

однако Apple недавно изменила реализации этих методов, чтобы сохранить + освободить свои аргументы, которые, очевидно, взорвутся, когда этот аргумент содержит BOOL или другой не-объект тип.

хотя я создал вспомогательные методы в прошлом, мой любимый метод в настоящее время-использовать Более Того,, например:

[[myButton onMainThread] setEnabled:YES];

на NSInvocation используется в реализации HOM заботится об обертывании и разворачивании всех примитивных типов, а синтаксис HOM позволяет легко вводить и очищать.

я назвал эту технику Небольшое Сообщение Отправка.