0

我正在尝试重构一些NSJSONSerialization代码,使其不在主线程上。目前该应用程序有点迟钝。

我想将此代码重构为下面的代码,并且遇到语法问题,尤其是错误处理方面的问题。例如,如果我采用现有代码(requestData: 方法)并将其放入

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
});

该表不再加载任何数据。

谢谢你的帮助。

-(void)requestData {

    [HUD showUIBlockingIndicatorWithText:@"Fetching JSON"];

    NSError *requestError = nil;

    NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL
                                                          URLWithString:kURL]];

    NSData *response = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:&requestError];

    NSError *jsonParsingError = nil;

    if (requestError)
    {
        NSLog(@"sync. request failed with error: %@", requestError);
    }
    else
    {
        // handle data
       publicData =  [NSJSONSerialization JSONObjectWithData:response
                                                                    options:0
                                                                      error:&jsonParsingError];
        publicDataArray = [publicData objectForKey:@"data"];

    }

    /*
     for(publicDataDict in publicDataArray) {
     NSLog(@"data output is %@",[publicDataDict objectForKey:@"title"]);

     }
     */
    [self.mainTableView reloadData];

    [HUD hideUIBlockingIndicator];
}

这是我想使用的代码。

-(void)viewDidAppear:(BOOL)animated
{

    [HUD showUIBlockingIndicatorWithText:@"Fetching Data"];

    //1
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        //code executed in the background
        //2
        NSData* ghData = [NSData dataWithContentsOfURL:
                            [NSURL URLWithString:kURL]
                            ];
        //3
        NSDictionary* json = nil;
        if (ghData) {
            json = [NSJSONSerialization
                    JSONObjectWithData:ghData
                    options:kNilOptions
                    error:nil];
        }

        //4
        dispatch_async(dispatch_get_main_queue(), ^{
            //code executed on the main queue
            //5


            [self.tableView reloadData];
            [HUD hideUIBlockingIndicator];
        });

    });
}
4

4 回答 4

2

很多人认为将进程发送到后台会自动消除他们的应用程序的任何迟缓,这是一个错误的假设。如果您将 CPU 密集型任务发送到后台,它也会阻塞 CPU。为了使多线程对您有利,您必须有条不紊地处理它。

现在到你的问题上,最简单的解决方案是让你使用 Apple 已经提供的东西,NSURLConnection 是你最好的选择,永远不要使用 [NSData dataWithContentsOfURL:] 这绝对不是。问题不是 NSJSONSerialization,而是网络请求。

你真的有两个选择。

1) 使用 NSRULConnection 委托方法并将您的 JSON 序列化方法放在 - connectionDidFinishLoading: 委托方法中

2)使用 NSURLConnection [NSURLConnection sendAsynchronousRequest: queue: completionHandler:] 的块方法(我的首选)

-(void)viewDidAppear:(BOOL)animated
{
    [HUD showUIBlockingIndicatorWithText:@"Fetching Data"];

    NSURLRequest *request = [NSURLRequest requestWithURL:URL];
    [NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) {

    if (!error) {
        NSError *jsonError = nil;
        NSDictionary *jsonDict = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:&jsonError];

        if (jsonError) {
            NSLog(@"Error parsing JSON");
            //Optionally display error message here
        }else{

            self.globalDictionary = jsonDict;

            [self.tableView reloadData];
            [HUD hideUIBlockingIndicator];
        }

    }else
    {
        NSLog(@"Error with request");

        [HUD hideUIBlockingIndicator];
        //Optionally display error message here
    }


}];

}

注意: globalDictionary 是一个填充表格的 NSDictionary 实例。

于 2013-07-03T11:06:26.080 回答
1

所以可能的猜测是,可能会更早地调用 table reload 方法。所以最后你可以重新加载表格,如下所示。

-(void)viewDidAppear:(BOOL)animated
{

    [HUD showUIBlockingIndicatorWithText:@"Fetching Data"];

    //1
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        //code executed in the background
        //2
        NSData* ghData = [NSData dataWithContentsOfURL:
                          [NSURL URLWithString:kURL]
                          ];
        //3
        NSDictionary* json = nil;
        if (ghData) {
            json = [NSJSONSerialization
                    JSONObjectWithData:ghData
                    options:kNilOptions
                    error:nil];
        }

        //4
        [self performSelectorOnMainThread:@selector(reloadTable) withObject:nil waitUntilDone:NO];

    });
}

在此之后这样做。

-(void)reloadTable {

    [self.tableView reloadData];
    [HUD hideUIBlockingIndicator];
}

还要检查是否调用了 tableview 数据源委托方法,如果它没有被调用,然后设置 UITableView 委托。

于 2013-07-03T10:53:41.730 回答
0

如果要重构代码,请使用函数。您应该编写旨在在单独的函数中执行某些任务的逻辑/代码,并且在正常情况下,任何函数中的 LOC 不应超过 20。

谈到您的问题,看起来您说得对,但我没有看到您定义 tableView 的源,请检查您是否已将 JSON 转换为任何容器对象即字典或数组。

    -(void)viewDidAppear:(BOOL)animated
{
    [HUD showUIBlockingIndicatorWithText:@"Fetching Data"];

    [self fetchData];
}

-(void)fetchData
{
  dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
  // switch to a background thread and perform your expensive operation

  NSData* ghData = [NSData dataWithContentsOfURL:
                            [NSURL URLWithString:kURL]
                            ];

  NSDictionary* json = nil;

  if (ghData) 
  {
    json = [NSJSONSerialization
                    JSONObjectWithData:ghData
                    options:kNilOptions
                    error:nil];
   }

   dispatch_async(dispatch_get_main_queue(), ^{
   // switch back to the main thread to update your UI
  [self.tableView reloadData];
  [HUD hideUIBlockingIndicator];
    });

 });
}
于 2013-07-03T10:37:23.810 回答
-3

首先尝试重构以将项目转换为新架构 ARC,我将其发布在旧答案中,请看这里:

我的帖子

希望这对您有所帮助或提供重构代码的想法;)

于 2013-07-03T10:06:47.987 回答