简体   繁体   English

iOS:后台运行期间主线程速度变慢

[英]IOS: Main thread slowing down during background operation

I am using the following code to conduct what I want to be a background sync but the main thread is slowing down or even coming to a halt when the json received is larger than 20 or so records. 我正在使用以下代码来进行我想成为后台同步的操作,但是当接收到的json大于20个左右记录时,主线程正在减慢速度甚至停止运行。 Is there anything wrong with this code for a background operation? 此代码的后台操作有什么问题吗? What could be blocking the main thread. 什么可能会阻塞主线程。 Thank you for any suggestions. 感谢您的任何建议。

Note there is a commented out line below performSelectorOnMainThread where the app processes the JSON received that I changed to yet another background thread but the change does not seem to help. 请注意,在performSelectorOnMainThread下面有一条注释行,其中应用程序处理了我收到的已更改为另一个后台线程的JSON,但此更改似乎无济于事。

#define kBgQueue dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0) //1
#define kProductsURL [NSURL URLWithString: @"http://~/getproducts.php"]

//in viewDidLoad
if(hasInternet==YES && [loggedIntoServer isEqual:@1]) {

        dispatch_async(kBgQueue, ^{
            NSData* data = [NSData dataWithContentsOfURL: kProductsURL];
              //previous line grabed data from api.
            if (data) {
         //   [self performSelectorOnMainThread:@selector(fetchData:) withObject:data waitUntilDone:YES];//no longer doing this on main thread
                dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
                    [self fetchData:data];
                });

                }
        });
              ;
    } //close hasInternet, logged into server.



  - (void)fetchData:(NSData *)jsonFeed {
    NSError* error;
    NSDictionary* json = [NSJSONSerialization JSONObjectWithData:jsonFeed
                                                         options:kNilOptions
                                                           error:&error];
    NSMutableArray* latestProducts = [[NSMutableArray alloc] init];
    //this is specific to format of JSON
    if (![[json objectForKey:@“products"] isKindOfClass:[NSNull class]]) {
            latestProducts = [[json objectForKey:@“products"]mutableCopy];
    getProducts = latestProducts;
    int size = [latestProducts count];
    [self.tableView reloadData];
    getProducts = [self convertFeedtoObject:latestProducts];
    [self importAndSaveProducts:getProducts];//this imports and saves
    self.recentlySynced=YES;
     }
}

You do not need to have a nested call to the same queue. 您无需对同一队列进行嵌套调用。 Also you should do any UI work on the main thread. 另外,您应该在主线程上执行任何UI工作。 For more information look at Apple's Concurrency Programming Guide 有关更多信息,请参阅《 Apple 并发编程指南》。

In your fetchData method load your table like this. 在您的fetchData方法中,像这样加载表格。

dispatch_async(dispatch_get_main_queue(), {
    // Your UI work 
    [self.tableView reloadData];

})


 // Remove second dispatch_async call 

 //in viewDidLoad
if(hasInternet==YES && [loggedIntoServer isEqual:@1]) {

        dispatch_async(kBgQueue, ^{
            NSData* data = [NSData dataWithContentsOfURL: kProductsURL];
              //previous line grabed data from api.
            if (data) {
                [self fetchData:data];

                }
        });
              ;
} //close hasInternet, logged into server.

You just did something redundant. 您只是做了多余的事情。 You dispatched the fetching of data in a background thread. 您在后台线程中调度了数据获取。 But then you also did the [self.tableView reloadData]; 但是随后您也做了[self.tableView reloadData]; in the background thread. 在后台线程中。 That's why your UI will be affected. 这就是为什么您的用户界面会受到影响的原因。

Try this: 尝试这个:

if(hasInternet==YES && [loggedIntoServer isEqual:@1]) 
{
    dispatch_async(kBgQueue, ^
    {
        NSData* data = [NSData dataWithContentsOfURL: kProductsURL];

        if (data) 
        {
              dispatch_async(dispatch_get_main_queue(), ^
              {
                  [self fetchData:data];
              });
        }
    });
}

What I did is I changed this part of your code: 我所做的是更改了代码的这一部分:

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
                    [self fetchData:data];
                });

Because you should only do any changes to UI in the main thread. 因为您只应在主线程中对UI进行任何更改。 and this part of my code is doing the job in main thread. 我的代码的这一部分正在主线程中完成工作。

dispatch_async(dispatch_get_main_queue(), ^
                  {
                      [self fetchData:data];
                  });

There are several errors in your original code, change to the following: 您的原始代码中有几个错误,请更改为以下内容:

#define kBgQueue dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0) //CHANGE TO BACKGROUND
#define kProductsURL [NSURL URLWithString: @"http://~/getproducts.php"]

//in viewDidLoad
if(hasInternet==YES && [loggedIntoServer isEqual:@1]) {
        dispatch_async(kBgQueue, ^{
            NSData* data = [NSData dataWithContentsOfURL: kProductsURL];
            if (data) {             
                [self fetchData:data];
            }
        });
    } //close hasInternet, logged into server.

Change the fetch data to the following: 将获取数据更改为以下内容:

- (void)fetchData:(NSData *)jsonFeed {
    NSError* error;
    NSDictionary* json = [NSJSONSerialization JSONObjectWithData:jsonFeed
                                                         options:kNilOptions
                                                           error:&error];

    NSMutableArray* latestProducts = [[NSMutableArray alloc] init];

    //this is specific to format of JSON
    if (![[json objectForKey:@"products"] isKindOfClass:[NSNull class]]) {

        latestProducts = [[json objectForKey:@"products"]mutableCopy];

        getProducts = latestProducts;
        int size = [latestProducts count];

        //Do this on the main thread:
        dispatch_async(dispatch_get_main_queue(), ^{
            [self.tableView reloadData];
        });

        getProducts = [self convertFeedtoObject:latestProducts];
        [self importAndSaveProducts:getProducts];//this imports and saves
        self.recentlySynced=YES;
     }
}

Depending on how your table view works and what the data source is like, you may want to move the reload table view line (with the main queue dispatch) to underneath self.recentSynced = YES. 根据表视图的工作方式以及数据源的类型,您可能希望将重载表视图行(使用主队列调度)移动到self.recentSynced = YES下方。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM