分离的 NSThread 中的内存分配以在后台加载 NSDictionary?
我正在尝试启动后台线程以从 Web 服务检索 XML 数据。我同步开发它 - 没有线程,所以我知道该部分可以工作。现在我准备通过生成一个线程来等待响应和解析来获得非阻塞服务。
我在线程内创建了一个 NSAutoreleasePool 并在解析结束时释放它。生成的代码和线程如下:
从主循环代码生成:
.
.
[NSThread detachNewThreadSelector:@selector(spawnRequestThread:)
toTarget:self withObject:url];
.
.
线程(“self”内部):
-(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:@""];
}
I am trying to launch a background thread to retrieve XML data from a web service. I developed it synchronously - without threads, so I know that part works. Now I am ready to have a non-blocking service by spawning a thread to wait for the response and parse.
I created an NSAutoreleasePool inside the thread and release it at the end of the parsing. The code to spawn and the thread are as follows:
Spawn from main-loop code:
.
.
[NSThread detachNewThreadSelector:@selector(spawnRequestThread:)
toTarget:self withObject:url];
.
.
Thread (inside 'self'):
-(void) spawnRequestThread: (NSURL*) url {
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
parser = [[NSXMLParser alloc] initWithContentsOfURL:url];
[self parseContentsOfResponse];
[parser release];
[pool release];
}
The method parseContentsOfResponse
fills an NSMutableDictionary with the parsed document contents. I would like to avoid moving the data around a lot and allocate it back in the main-loop that spawned the thread rather than making a copy. First, is that possible, and if not, can I simply pass in an allocated pointer from the main thread and allocate with 'dictionaryWithDictionary' method? That just seems so inefficient.
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;
}
First parse section
Each section creates element strings when its elementStart is signaled. The elementEnd will add the object to the dictionary and release the element. The remaining details are redundant and I think the point to note is that the allocations are not directed at an NSZone, therefore they should be residing in the thread's memory pool.
- (void)parserDidStartDocument:(NSXMLParser *)parser {
NSLog(@"%s", __FUNCTION__);
currentChars = [NSMutableString stringWithString:@""];
elementQuestion = [NSMutableString stringWithString:@""];
elementAnswer = [NSMutableString stringWithString:@""];
elementKeyword = [NSMutableString stringWithString:@""];
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
最简单的方法是在单独的线程中创建字典,然后将其设置为主线程上的属性,如下所示:
您需要随着时间的推移更改字典的内容吗?如果是这样,在主线程上分配并更改另一个线程中的内容是可能的,但你必须担心线程安全问题 -
NSMutableDictionary
不是线程安全的,所以你必须使用原子属性和锁:在任何情况下,锁定都非常昂贵且效率低下,因此我倾向于更喜欢第一种方法(我不确定哪种方法更昂贵,确切地说,但第一种更简单并且避免了线程-安全问题)。
另外,查看您的代码,您的
NSXMLParser
看起来像是您直接访问的 ivar。这是一个坏主意,因为NSXMLParser
不是线程安全的——我建议将其实现为局部变量。如果您确实需要它作为 ivar,请使用原子属性和锁,并且仅通过访问器访问它。The simplest thing to do would be to create the dictionary in the separate thread, then set it as a property on the main thread, like so:
Do you need to change the contents of the dictionary over time? If so, allocating on the main thread and changing the contents in the other thread is possible, but you have to worry about thread-safety issues--
NSMutableDictionary
isn't thread-safe, so you'd have to use an atomic property and locks:Locking is quite expensive and inefficient in any case, so I'd tend to prefer the first method (I'm not sure which is more expensive, exactly, but the first is simpler and avoids thread-safety issues).
Also, looking at your code, it looks like your
NSXMLParser
is an ivar which you directly access. This is a bad idea, sinceNSXMLParser
isn't thread-safe--I would recommend implementing it as a local variable instead. If you do need it as an ivar, use an atomic property and locks and only access it through accessors.