如何重构代码,使其不在主线程上

时间:2013-07-03 09:50:19

标签: iphone ios objective-c nsjsonserialization

我正在尝试重构一些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 个答案:

答案 0 :(得分:2)

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

现在解决你的问题,最简单的解决方案就是让你使用Apple提供的东西,NSURLConnection是你最好的选择,永远不要使用[NSData dataWithContentsOfURL:]这是一个明确的不。 问题不在于NSJSONSerialization,而是网络请求。

你真的有两种选择。

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

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实例。

答案 1 :(得分:1)

因此,可能的猜测是这可能是表重载方法将在之前调用。所以在最后你可以重新加载表格,如下所示。

-(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委托。

答案 2 :(得分:0)

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

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

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

 });
}

答案 3 :(得分:-3)

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

My Post

希望这可以帮助您或提供重构代码的想法;)