关于互联网上的每一个教程和示例,我看到了如何从某个URL获取JSON并在Tableview中显示它。这不是我的问题我知道如何使用AFNetworking框架或使用本机API。
我的问题是在我下载了JSON之后,我想在我的UIView标签中显示一些内容。当我试图找到解决NSURLSession无法在iOS 8中缓存的方法时,我实际上成功了。但我没有意识到它是同步的。
Factory.m
+ (Factory *)responseJson
{
static Factory *shared = nil;
shared = [[Factory alloc] init];
NSHTTPURLResponse *response = nil;
NSString *jsonUrlString = [NSString stringWithFormat:@"http://urltojson.com/file.json"];
NSURL *url = [NSURL URLWithString:[jsonUrlString stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
NSError *error = nil;
NSURLRequest *request = [NSURLRequest requestWithURL:url
cachePolicy:NSURLRequestReturnCacheDataElseLoad
timeoutInterval:10.0];
NSData *responseData = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
if (error) {
NSLog(@"error");
} else {
//-- JSON Parsing
NSDictionary *result = [NSJSONSerialization JSONObjectWithData:responseData options:kNilOptions error:nil];
//NSLog(@"Result = %@",result);
shared.responseJson = result;
}
return shared;
}
我的问题是否可以使用例如AFNetwoking来做同样的事情?我错过了一些我需要调用的方法,就像TableView
一样[self.tableView reloadData];
我想使用该框架,因为我需要检查Reachability,它似乎已经实现了它。
按要求编辑以显示更多代码
ViewController.m
- (void)viewDidLoad
{
[super viewDidLoad];
[self factoryLoad];
[self setupView];
}
- (void)factoryLoad
{
Factory *shared = [Factory responseJson];
self.titles = [shared.responseJson valueForKeyPath:@"data.title"];
dispatch_async(dispatch_get_main_queue(), ^{
[self.collectionView reloadData];
});
}
- (void)setupView
{
self.issueTitleLabel.text = [self.titles objectAtIndex:0];
}
答案 0 :(得分:0)
您发布的代码中有几个奇怪的地方。
dispatch_once
内实例化看似单身类的工厂,以确保线程安全。ViewController.m
中,您在主线程上调用factoryLoad
,然后在主线程上调用sendSynchronousRequest
。 Apple's NSURLConnection Documentation警告不要在主线程上调用此函数,因为它会阻塞线程,使您的应用程序无法响应用户输入。nil
作为NSJSONSerialization JSONObjectWithData:
中的错误参数传递。在你的情况下,我建议将数据的提取与单个对象的构造分开。
Factory.m
+(Factory *)sharedFactory {
static Factory *sharedFactory = nil;
dispatch_once_t onceToken;
dispatch_once(&onceToken, {
sharedFactory = [[Factory alloc] init];
});
}
-(void)fetchDataInBackgroundWithCompletionHandler:(void(^)(NSURLResponse *response,
NSData *data,
NSError *error)
completion {
NSHTTPURLResponse *response = nil;
NSString *jsonUrlString = [NSString stringWithFormat:@"http://urltojson.com/file.json"];
NSURL *url = [NSURL URLWithString:[jsonUrlString stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
NSURLRequest *request = [NSURLRequest requestWithURL:url
cachePolicy:NSURLRequestReturnCacheDataElseLoad
timeoutInterval:10.0];
NSOperationQueue *downloadQueue = [[NSOperationQueue alloc] init];
[NSURLConnection sendAsynchronousRequest:request
queue:downloadQueue
completionHandler:completion];
}
现在,您应该能够创建对数据的引用,并保证下载请求已完成,因此数据将存在。
ViewController.m
-(void)factoryLoad {
[[Factory sharedFactory] fetchDataInBackgroundWithCompletionHandler:^(void)(NSURLResponse *response, NSData *data, NSError *error){
if(!error) {
NSError *error2;
NSDictionary *serializedData = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:&error2];
if(error2){ /* handle error */ }
self.titles = [serializedData valueForKeyPath:@"data.title"];
[Factory sharedFactory].responseJSON = serializedData;
}
else {
// handle error
}
}];
}
这将保证在您尝试访问任何下载的信息之前已完成下载。但是,我在这里留下了一些东西,包括向用户显示应用程序在后台执行重要操作的任何类型的活动指示器。其余的,呃,留给读者练习。
答案 1 :(得分:0)
好的,我对Morgan Chen的回答以及如何阻止进行了更深入的调查。
示例代码进行了一些修改,但我认为它的工作原理应该是更好的代码。
在Factory.m
+ (Factory *) sharedInstance
{
static Factory *_sharedInstance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_sharedInstance = [[self alloc] init];
});
return _sharedInstance;
}
-(void)fetchDataInBackgroundWithCompletionHandler: (void(^)(BOOL success, NSDictionary *data, NSError *error)) block
{
NSString * baseURL = @"http://jsonurl.com/file.json";
AFHTTPRequestOperationManager * manager = [[AFHTTPRequestOperationManager alloc] init];
__weak AFHTTPRequestOperationManager *weakManager = manager;
NSOperationQueue *operationQueue = manager.operationQueue;
[manager.reachabilityManager setReachabilityStatusChangeBlock:^(AFNetworkReachabilityStatus status) {
switch (status) {
case AFNetworkReachabilityStatusReachableViaWWAN:
case AFNetworkReachabilityStatusReachableViaWiFi:
NSLog(@"internet!");
[weakManager.requestSerializer setCachePolicy:NSURLRequestReloadIgnoringCacheData];
[operationQueue setSuspended:NO];
break;
case AFNetworkReachabilityStatusNotReachable:
NSLog(@"no internet");
[weakManager.requestSerializer setCachePolicy:NSURLRequestReturnCacheDataElseLoad];
[operationQueue setSuspended:YES];
break;
default:
break;
}
}];
[manager.reachabilityManager startMonitoring];
manager.responseSerializer = [AFJSONResponseSerializer serializer];
[manager GET:baseURL parameters:nil success:^(AFHTTPRequestOperation *operation, id responseObject) {
if (responseObject && [responseObject isKindOfClass:[NSDictionary class]]) {
block(YES, responseObject, nil);
}
} failure:^(AFHTTPRequestOperation *operation, NSError *error) { // invalid request.
NSLog(@"%@", error.localizedDescription);
block(NO, nil, error);
}];
}
在ViewController.m中我在viewDidLoad上调用此方法
-(void)factoryLoad
{
[[Factory sharedInstance] fetchDataInBackgroundWithCompletionHandler:^(BOOL success, NSDictionary *data, NSError *error) {
if (success) {
NSLog(@"we have stuff");
self.responseData = data;
self.titles = [self.responseData valueForKeyPath:@"data.title"];
[self setupView];
dispatch_async(dispatch_get_main_queue(), ^{
[self.collectionView reloadData];
});
}
}];
}