iOS 中的作用域和线程
Posted
技术标签:
【中文标题】iOS 中的作用域和线程【英文标题】:Scope and threading in iOS 【发布时间】:2013-04-23 13:36:00 【问题描述】:我对 ios 中的 Web 服务调用和线程有点陌生。我的应用程序中有一个ViewController
,其中包含一个表格视图控件。我正在使用通过 JSON Web 服务获得的数据填充表。 JSON Web 服务在其自己的线程上调用,在此期间我填充了NSArray
和NSDictionary
。
我的数组和字典似乎超出了范围,因为我的 NSLog
语句为数组计数返回零,即使在 fetchedData
中数组已完全填充。
有人可以解释为什么我的数组和字典对象在线程之外是空的吗?
- (void)viewDidLoad
[super viewDidLoad];
NSString *serviceEndpoint = [NSString stringWithFormat:
@"http://10.0.1.12:8888/platform/services/_login.php?un=%@&pw=%@&ref=%@",
[self incomingUsername], [self incomingPassword], @"cons"];
NSURL *url = [NSURL URLWithString:serviceEndpoint];
dispatch_async(kBgAdsQueue, ^
NSData *data = [NSData dataWithContentsOfURL:url];
[self performSelectorOnMainThread:@selector(fetchedData:) withObject:data waitUntilDone:YES];
);
NSLog(@"ARRAY COUNT: %d\n", [jsonArray count]);
-(void)fetchedData:(NSData*)responseData
NSError *error;
jsonDict = [NSJSONSerialization JSONObjectWithData:responseData options:kNilOptions error:&error];
jsonArray = [[jsonDict allKeys]sortedArrayUsingSelector:@selector(compare:)];
for(NSString *s in jsonArray)
NSLog(@"%@ = %@\n", s, [jsonDict objectForKey:s]);
【问题讨论】:
ViewDidLoad
仅在屏幕首次加载时被调用。您确定在此之前调用了fetchedData
吗?
【参考方案1】:
当您使用dispatch_async
时,该位代码不会阻塞。这意味着您的数组计数日志语句在调用fetchedData
之前触发,因此您的字典和数组仍然为空。查看日志语句的顺序 - 您应该在记录字典之前看到数组计数。
// Executes on another thread. ViewDidLoad will continue to run.
dispatch_async(kBgAdsQueue, ^
NSData *data = [NSData dataWithContentsOfURL:url];
[self performSelectorOnMainThread:@selector(fetchedData:) withObject:data waitUntilDone:YES];
);
// Executes before the other thread has finished fetching the data. Objects are empty.
NSLog(@"ARRAY COUNT: %d\n", [jsonArray count]);
您需要在数据返回后完成对TableView
的填充(即在FetchData:
中)。
【讨论】:
是的,这很有道理,但现在我不知道如何纠正这个问题。我需要在线程上执行此操作,因为这可能需要一些时间... 只需从 fetchedData 函数中调用 TableView 上的 reloadData。 您应该在您的 UI 上显示它正在下载的某种指示 - 可能是一个微调器或一个读取类似“正在获取数据。这可能需要一分钟”的单元格。这样用户就知道发生了什么事。当fetchData:
触发时,您可以调用reloadData
。或者,如果请求失败,您可以触发新的显示消息。
将 fetch 从视图控制器中移出到模型对象中。视图控制器不应该做网络访问;他们应该显示在模型中找到的数据。因此模型根据需要获取数据,视图控制器只显示模型当前包含的任何内容。【参考方案2】:
viewDidLoad 中的日志语句应该报告该数组是空的,因为当时它还没有被填充。调用 dispatch_async 会导致该代码块异步运行,并允许 viewDidLoad 函数在该块之前完成。这就是为什么在 viewDidLoad 结束时数组中没有任何内容的原因。
【讨论】:
【参考方案3】:您正在尝试在填充之前打印 jsonArray 元素的计数。这是发生了什么:
-
你准备网址
您创建新线程来获取某个日期。此线程的执行可能需要一些时间(取决于连接速度和数据量)。
您正在访问 jsonArray,而线程正在执行并且 fetchedData: was not called
另外,建议: 不要使用 dataWithContentsOfURL: 方法。最好看看一些网络框架,例如 AFNetworking。
【讨论】:
以上是关于iOS 中的作用域和线程的主要内容,如果未能解决你的问题,请参考以下文章