我正在尝试启动后台线程以从Web服务检索XML数据。我同步开发它 - 没有线程,所以我知道那部分有用。现在我准备通过生成一个等待响应和解析的线程来获得非阻塞服务。
我在线程中创建了一个NSAutoreleasePool,并在解析结束时释放它。产生的代码和线程如下:
从主循环代码中生成:
.
.
[NSThread detachNewThreadSelector:@selector(spawnRequestThread:)
toTarget:self withObject:url];
.
.
主题(在'自我'内部):
-(void) spawnRequestThread: (NSURL*) url {
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
parser = [[NSXMLParser alloc] initWithContentsOfURL:url];
[self parseContentsOfResponse];
[parser release];
[pool release];
}
方法parseContentsOfResponse
用解析的文档内容填充NSMutableDictionary。我想避免大量移动数据并将其分配回产生线程的主循环而不是复制。首先,这是可能的,如果没有,我可以简单地从主线程传入一个已分配的指针并使用'dictionaryWithDictionary'方法进行分配吗?这似乎效率低下。
parseContentsOfResponse
-(void)parseContentsOfResponse {
[parser setDelegate:self];
[parser setShouldProcessNamespaces:YES];
[parser setShouldReportNamespacePrefixes:YES];
[parser parse];
NSError *parseError = [parser parserError];
if (parseError) {
NSLog(@"%@", parseError);
NSLog(@"publicID: %@", [parser publicID]);
NSLog(@"systemID: %@", [parser systemID]);
NSLog(@"line:%d column:%d", [parser lineNumber], [parser columnNumber]);
}
ready = YES;
}
第一个解析部分
每个部分在发出elementStart信号时都会创建元素字符串。 elementEnd将对象添加到字典中并释放元素。其余的细节是多余的,我认为需要注意的是,分配不是针对NSZone的,因此它们应该驻留在线程的内存池中。
- (void)parserDidStartDocument:(NSXMLParser *)parser {
NSLog(@"%s", __FUNCTION__);
currentChars = [NSMutableString stringWithString:@""];
elementQuestion = [NSMutableString stringWithString:@""];
elementAnswer = [NSMutableString stringWithString:@""];
elementKeyword = [NSMutableString stringWithString:@""];
}
答案 0 :(得分:1)
最简单的方法是在单独的线程中创建字典,然后将其设置为主线程上的属性,如下所示:
- (void)spawnRequestThread: (NSURL*) url {
NSMutableDictionary *dict = [[NSMutableDictionary alloc] init];
//do stuff with dict
[self performSelectorOnMainThread:@selector(doneWithThread:) withObject:dict waitUntilDone:NO];
}
- (void)doneWithThread:(NSDictionary *)theDict {
self.dict = theDict; //retaining property, can be an NSDictionary
}
您是否需要随着时间的推移更改字典的内容?如果是这样,可以在主线程上分配并更改另一个线程中的内容,但是你必须担心线程安全问题 - NSMutableDictionary
不是线程安全的,所以你必须使用原子属性和锁:
//.h
@property (retain) NSMutableDictionary *dict; //don't use "nonatomic" keyword
@property (retain) NSLock *dictLock;
//.m
- (id) init {
//blah blah
dict = [[NSMutableDictionary alloc] init];
dictLock = [[NSLock alloc] init];
return self;
}
- (void)spawnRequestThread: (NSURL*) url {
//whenever you have to update the dictionary
[self.dictLock lock];
[self.dict setValue:foo forKey:bar];
[self.dictLock unlock];
}
锁定在任何情况下都非常昂贵且效率低下,所以我倾向于选择第一种方法(我不确定哪种方法更昂贵,但确实更简单并且避免了线程安全问题)。
此外,查看您的代码,您的NSXMLParser
似乎是您直接访问的ivar。这是一个坏主意,因为NSXMLParser
isn't thread-safe - 我建议将其作为局部变量实现。如果确实需要它作为ivar,请使用原子属性并锁定,只能通过访问器访问它。