【问题标题】:How to show JSON data in UIView labels如何在 UIView 标签中显示 JSON 数据
【发布时间】:2014-10-29 18:11:18
【问题描述】:

关于我在互联网上看到的每一个教程和示例,都展示了如何从某个 url 获取 JSON 并将其显示在 Tableview 中。这不是我的问题,我知道如何使用 AFNetworking 框架或原生 API 来做到这一点。

我的问题是,在我下载了 JSON 之后,我想在我的 UIView 标签中显示其中的一些。当我试图找到解决 NSURLSession 无法在 iOS 8 中缓存的方法时,我实际上已经成功地做到了这一点。但我没有意识到它是同步的。

工厂.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]; 

我想使用那个框架,因为我需要检查可达性,而且它似乎已经实现了。

按要求编辑以显示更多代码

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];
}

【问题讨论】:

  • 那么,您尝试将数据放入标签的哪个位置?
  • 在 viewDidLoad 中。使用异步获取方法,我尝试将获取方法放在 viewWillAppear 中并在 viewDidLoad 中设置所有标签,但这没有用。
  • 您可以编辑您的问题并显示用于设置标签文本的代码吗?如果您正在异步获取数据并在完成处理程序之外设置标签文本,您可能会尝试将文本设置为实际不存在的值,因为尚未获取数据。
  • 好吧,在你收到数据之前你不能使用它。
  • 嗯,我明白了。我想我只是将网络代码保留在 ViewController 中。

标签: objective-c json ios7 uiview afnetworking-2


【解决方案1】:

您发布的代码中有一些奇怪之处。

  • Factory 似乎是一个单例类,应在 dispatch_once 内实例化以确保线程安全。
  • ViewController.m 中,您在主线程上调用factoryLoad,随后在主线程上调用sendSynchronousRequestApple's NSURLConnection Documentation 警告不要在主线程上调用此函数,因为它会阻塞线程,使您的应用程序无法响应用户输入。
  • 您不应将nil 作为NSJSONSerialization JSONObjectWithData: 中的错误参数传递。

在您的情况下,我建议将数据获取与单例对象的构造分开。

工厂.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
        }
    }];
}

这将保证在您尝试访问任何已下载信息之前下载已完成。但是,我在这里留下了一些东西,包括向用户显示应用程序正在后台执行重要操作的任何类型的活动指示器。剩下的,呃,留给读者作为练习。

【讨论】:

  • 是的,我知道在主线程上进行同步调用是不好的,但在这种情况下,我只在应用程序启动时获取一次数据并缓存它,因此它不会真正阻塞任何东西。无论如何,这段代码并没有真正帮助我,因为我试图实现 AFNetworking 的可达性方法。
【解决方案2】:

好的,我对 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];

        });

    }
}];
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-09-29
    • 2021-01-10
    • 2021-09-07
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多