5

我正在开发一个需要在后台线程中构建一些图像的应用程序。在此过程中的某个时刻,我需要从 UITextView 获取文本。如果我调用 UITextview.text,我会收到警告说我的辅助线程不应该纠缠 UIKit

这一切都很好,但我需要文本,我无法找到一种合理的方式从主线程中获取所述文本。

我的问题是:有没有人想出一种从后台线程中获取 UI 元素属性的好方法,或者,是否有好的方法首先避免这样做?

我把这个东西放在一起,它成功了,但感觉不太对劲:

@interface SelectorMap : NSObject

@property (nonatomic, strong) NSArray *selectors;
@property (nonatomic, strong) NSArray *results;

@end


@interface NSObject (Extensions)
- (NSArray *)getValuesFromMainThreadWithSelectors:(SEL)selector, ...;
- (void)performSelectorMap:(SelectorMap *)map;
@end

和实施:

#import "NSObject+Extensions.h"

@implementation SelectorMap
@synthesize selectors;
@synthesize results;
@end

@implementation NSObject (Extensions)

- (void)performSelectorMap:(SelectorMap *)map
{
    NSMutableArray *results = [NSMutableArray arrayWithCapacity:map.selectors.count];

    for (NSString *selectorName in map.selectors)
    {
        SEL selector = NSSelectorFromString(selectorName);
        id result = [self performSelector:selector withObject:nil];
        [results addObject:result];
    }

    map.results = results.copy;
}

- (NSArray *)getValuesFromMainThreadWithSelectors:(SEL)selector, ...
{
    NSMutableArray *selectorParms = [NSMutableArray new];

    va_list selectors;
    va_start(selectors, selector);

    for (SEL selectorName = selector; selectorName; selectorName = va_arg(selectors, SEL))
        [selectorParms addObject:NSStringFromSelector(selectorName)];

    va_end(selectors);

    SelectorMap *map = [SelectorMap new];
    map.selectors = selectorParms.copy;

    [self performSelectorOnMainThread:@selector(performSelectorMap:) withObject:map waitUntilDone:YES];

    return map.results;
}

@end

我这样称呼它:

NSArray *textViewProperties = [textView getValuesFromMainThreadWithSelectors:@selector(text), @selector(font), nil];

获取字体不会给出与获取文本相同的警告,但我认为最好保持一致。

4

2 回答 2

17

我尽可能避免任何类型的元编程。它完全破坏了编译器对您的代码进行仔细检查的能力,并且它往往是不可读的。

 __block NSString* foo;
 dispatch_sync(dispatch_get_main_queue(), ^{
      foo = [textField ...];
  });

请注意,如果不使用 ARC,您可能希望在块中copy使用字符串,retain然后在本地线程中使用。releaseautorelease

于 2013-01-13T23:29:53.333 回答
2

您可以在主线程上使用 performSelector,也可以使用 GCD 在主队列上调度。

[self performSelectorOnMainThread:@selector(updateText:) withObject:nil waitUntilDone:YES];

GCD 看起来像:

dispatch_queue_t main = dispatch_get_main_queue();

dispatch_sync(main, ^{
  // read and assign here
});

这是有关该主题的相关帖子:

GCD、线程、程序流程和 UI 更新

于 2013-01-13T23:32:42.883 回答