我正在使用下面的代码,该代码在嵌入 UITableView
的 UIViewController
中调用。
它遍历一个位置列表,创建 NSURL
并将其传递给 NSXMLParser
。一切都按预期进行。
但是,如果用户单击后退按钮,我希望不仅 UIViewController
被解除并且用户返回到我之前的 UIViewController
已经,但我希望与 -(void)getInfo
和 NSXMLParser
中发生的 for 循环
相关的处理立即终止如果它确实仍在运行。
在大多数情况下,处理将完成,这不会成为问题,但是,在某些情况下,这可能需要更长的时间,我不希望代码在按下后继续运行, 因为这样就不需要数据了,因此只会浪费资源,并且由于处理多个 NSURL
s,在返回到前一个 UIViewController 时可能会阻塞 UI。
-(void)getInfo{
NSDictionary *places = [[NSDictionary alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForResource"places" ofType"plist"]];
NSArray *placescc = [[NSArray alloc] initWithArray:places.allKeys];
__block NSUInteger placewaiting = placescc.count;
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSDictionary *savedLocs = [[defaults objectForKey"savedLocs"]mutableCopy]; //got savedLocs
NSDictionary *thisLoc = [[savedLocs objectForKey:_LocId]mutableCopy]; //got this Loc
lastInfoCount = 0; // set default
if ([[thisLoc objectForKey"Infos"]count]){
lastInfoCount = [[thisLoc objectForKey"Infos"]count]; // set saved count if we have one
}
for (NSString *place in placescc) {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSURL *url = [NSURL URLWithString:[NSString stringWithFormat"http://url.com/%@/%@",place, LocIdString]];
NSXMLParser *parser = [[NSXMLParser alloc] initWithContentsOfURL:url];
dispatch_async(dispatch_get_main_queue(), ^{
[parser setDelegate:self];
[parser setShouldResolveExternalEntities:NO];
[parser parse];
placewaiting = placewaiting-1;
if (placewaiting == 0){
[self.tableView reloadData];
[self.activityIndicator stopAnimating];
lastRefresh = [NSString stringWithFormat"%@",[NSDate date]];
}
});
});
}
}
我建议使用 NSOperationQueue 和 NSBlockOperation 然后您可以取消在 dealloc(或可能是 viewWillDisappear)中的操作以及在 GCD 线程测试 isCanceled 上执行的 block 内并退出/跳过 UI 更新。但是,您必须确保对 View Controller 的弱引用,否则执行 block 将保留 Controller 。像这样的:
// @property(nonatomic,weak) NSBlockOperation *backgroundOperation;
+ (NSOperationQueue*)operationQueue
{
static dispatch_once_t onceToken;
static NSOperationQueue *operationQueue;
dispatch_once(&onceToken, ^{
operationQueue = [[NSOperationQueue alloc] init];
});
return operationQueue;
}
- (NSOperationQueue*)operationQueue
{
return [[self class] operationQueue];
}
- (void)dealloc
{
[self.backgroundOperation cancel];
}
- (void)getInfo
{
NSDictionary *places = [[NSDictionary alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForResource"places" ofType"plist"]];
NSArray *placescc = [[NSArray alloc] initWithArray:places.allKeys];
__block NSUInteger placewaiting = placescc.count;
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSDictionary *savedLocs = [[defaults objectForKey"savedLocs"]mutableCopy]; //got savedLocs
NSDictionary *thisLoc = [[savedLocs objectForKey:_LocId]mutableCopy]; //got this Loc
lastInfoCount = 0; // set default
if ([[thisLoc objectForKey:@"Infos"]count]){
lastInfoCount = [[thisLoc objectForKey:@"Infos"]count]; // set saved count if we have one
}
// Ensure previous operation finished
[self.backgroundOperation cancel];
NSBlockOperation *op = [[NSBlockOperation alloc] init];
self.backgroundOperation = op;
__weak NSBlockOperation *weakOp = op;
__weak typeof(self) weakSelf = self;
[op addExecutionBlock:^{
NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:@"http://url.com/%@/%@",place, LocIdString]];
NSXMLParser *parser = [[NSXMLParser alloc] initWithContentsOfURL:url];
if (weakOp && !weakOp.isCancelled)
{
dispatch_async(dispatch_get_main_queue(), ^{
[parser setDelegate:weakSelf];
[parser setShouldResolveExternalEntities:NO];
[parser parse];
placewaiting = placewaiting-1;
if (placewaiting == 0){
[weakSelf.tableView reloadData];
[weakSelf.activityIndicator stopAnimating];
lastRefresh = [NSString stringWithFormat:@"%@",[NSDate date]];
}
});
}
}];
[[self operationQueue] addOperationp];
}
请注意,weakSelf、weakOp 和 backgroundOperation 属性在其引用的对象被释放时将自动为 null,因此如果在 View Controller 关闭后执行 block 中的 UI 更新代码,weakSelf.tableView/activityIndicator 将为 null 并且没有操作。在您的情况下,因为大部分工作是同步检索和解析数据,因此不会中止,但上面的代码意味着 View Controller 将立即释放,并且 View Controller 上的 UI 更新变为无操作。
关于iOS 在解除 ViewController 时停止 for 循环内的所有当前处理,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23492250/
欢迎光临 OStack程序员社区-中国程序员成长平台 (https://ostack.cn/) | Powered by Discuz! X3.4 |