2013-01-13 68 views
4

我正在研究一个应用程序,我需要在后台线程中构建一些图像。在这个过程中的某个时刻,我需要从UITextView中获取文本。如果我打电话给UITextview.text,我得到了我的辅助线程不应该纠缠的警告UIKit从主线程中返回值objective-c

这一切都很好,但我需要的文本,我不能找出合理的方式来获取说文字主线程。

我的问题是:有没有人想出一个很好的方式来从后台线程获取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]; 

获取字体并没有给出获取文本的相同警告,但我认为这是最好的 始终如一。

回答

14

我尽可能地避免了任何类型的元编程。它彻底破坏了编译器仔细检查代码的能力,对于开始而言,它往往是不可读的。

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

注意如果不使用ARC,你可能会想copyretain该块中的字符串,然后releaseautorelease在您的本地线程。

+0

严重的是,这是更好的方式!我寻找了几个小时试图找出正确的方法来做到这一点。 –

+0

+1用于指出内存管理和关于元编程的观点。 – bryanmac

+0

很久以前我才知道笑容比我聪明。随着静态分析仪的进步,它似乎也在更快地学习。 :) – bbum

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, Threads, Program Flow and UI Updating