dispatch_queue_t仍在阻止主线程 [英] dispatch_queue_t still blocking main thread

查看:53
本文介绍了dispatch_queue_t仍在阻止主线程的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想触发一种方法并使其在后台运行-我不在乎启动后它到底会发生什么.

I want to fire off a method and have it run in the background - I do not care what really happens to it after it is started.

因此,在我的主viewDidLoadMethod中,我拥有了所有通常的代码以及以下内容:

So in my main viewDidLoadMethod I have all of my usually code and this:

 dispatch_queue_t newImages = dispatch_queue_create("load image in background", NULL);
    dispatch_async(newImages, ^{
        [self getNewImages];
    });
    dispatch_release(newImages);

我的假设是将创建队列,然后将该函数调用设置为在后台线程中运行,并且我的应用程序将继续巡航.似乎并非如此.

My assumption was that the queue would be created and then that function call would be set to run in a background thread and my app would keep cruising along. That does not seem to be the case.

从该函数调用的所有内容是否已自动移至后台线程,或者我现在需要确保没有发生其他可能的阻塞调用.

Is everything that is called from that function automatically moved to the background thread or do I now need to make sure there are no other possible blocking calls happening.

编辑-被阻止的代码:

-(void) getNewImages
{
    NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *documentsPath = [paths objectAtIndex:0];
    NSString *lastImagesSyncDate = [defaults valueForKey:@"ImagesLastSyncDate"];

    dispatch_queue_t newImages = dispatch_queue_create("com.mydomain.app.newimagesinbackground", NULL);
    dispatch_async(newImages, ^{

        for (Manufacturer *m in self.manufacturers)
        {
            NSString *myurl = [NSString stringWithFormat: kNewImagesURL, m.ManufacturerID  ,lastImagesSyncDate];
            NSString *manufacturerID = [m.ManufacturerID stringValue];
            NSURL *url = [NSURL URLWithString:[myurl stringByReplacingOccurrencesOfString:@" " withString:@"%20"]];
            __block ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];
            [request setCompletionBlock:^{

                // Use when fetching text data
                NSString *responseString = [request responseString];
                NSString *fileName =[documentsPath stringByAppendingPathComponent: [NSString stringWithFormat:@"newimages%@.plist", manufacturerID]];
                [responseString writeToFile:fileName atomically:YES encoding:NSUTF8StringEncoding error:nil];
                NSArray *array = [[NSArray alloc] initWithContentsOfFile:fileName];

                for (NSDictionary* dict in array) {

                    NSString *fileName = [NSString stringWithFormat:@"%@/%@_tn.jpg?t=",manufacturerID, [[dict valueForKey:@"ItemID"]  stringByReplacingOccurrencesOfString:@" " withString:@"%20"]];
                    NSString *savePath = [documentsPath stringByAppendingPathComponent:fileName];
                    NSURL *url = [NSURL URLWithString: [[NSString stringWithFormat:kProductImagesURL, fileName]stringByAppendingString:lastImagesSyncDate]];

                    __block ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];
                    [request setCompletionBlock:^{

                        int statusCode = [request responseStatusCode];
                        if (statusCode==200) {
                            NSData *responseData = [request responseData];
                            [responseData writeToFile:[savePath stringByReplacingOccurrencesOfString:@"%20" withString:@" "] atomically:YES];
                        }  

                    }];
                    [request setFailedBlock:^{
                        //  NSError *error = [request error];
                    }];
                    [request startAsynchronous];  
                }

                [array release];     
            }];
            [request setFailedBlock:^{
                //  NSError *error = [request error];
            }];
            [request startAsynchronous];
        }

        dispatch_async(dispatch_get_main_queue(), ^{
            dispatch_release(newImages); //this executes on main thread
        });
    });
}

我假设这里仅创建了1个队列,所有添加到其中的调用一次都运行1,直到它们完成为止.我对此进行了多种尝试,将我的应用拖到了停止状态-它不会崩溃,但主线程正在爬行.

I would assume that there is only 1 queue created here with all of these calls added to it running 1 at a time until they are complete. I tried several variations of this and it drags my app to a grinding halt - it doesn't crash but the main thread is crawling.

更新: 所以终于让我意识到,队列中所有这些异步ASIHTTPRequest都在创建大量线程,因此更新了我的代码以使队列将这段代码的长期运行部分添加到队列中,而使用同步请求:

UPDATE: So it finally dawned on me that having all of those async ASIHTTPRequest inside my queue was creating a massive amount of threads, so updated my code to just have the queue add the long running part of this code to the queue and use a synchronous request instead:

 for (NSDictionary* dict in array) {
                dispatch_async(newImages, ^{  
                    NSString *fileName = [NSString stringWithFormat:@"%@/%@_tn.jpg?t=",manufacturerID, [[dict valueForKey:@"ItemID"]  stringByReplacingOccurrencesOfString:@" " withString:@"%20"]];
                    NSString *savePath = [documentsPath stringByAppendingPathComponent:fileName];
                    NSURL *url = [NSURL URLWithString: [[NSString stringWithFormat:kProductImagesURL, fileName]stringByAppendingString:lastImagesSyncDate]];

                    ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];
                    [request startSynchronous];
                    NSError *error = [request error];
                    if (!error) {
                        int statusCode = [request responseStatusCode];
                        if (statusCode==200) {
                            NSData *responseData = [request responseData];
                            [responseData writeToFile:[savePath stringByReplacingOccurrencesOfString:@"%20" withString:@" "] atomically:YES];
                        }  
                    }
                });
}

现在,我只需要弄清楚在哪里再次释放队列,就算没有运气,我也尝试了几种变体.

NOW I just need to figure out where to release the queue again, I have tried several variations with no luck.

推荐答案

我走了很长一段路,但最终使这个想法浮现在脑海,这对我来说是完美的方法:

I went the long way around but finally got the concept in my head and here is what is working perfectly for me:

dispatch_queue_t newImages = dispatch_queue_create("com.mydomain.app.newimagesinbackground", NULL); // create my serial queue
        dispatch_async(newImages, ^{
     [self getNewImages]; // call my function - this get added first in my serial queue
    });


    dispatch_async(newImages, ^{
        dispatch_async(dispatch_get_main_queue(), ^{
            // add this to the main queue as the last item in my serial queue
            // when I get to this point I know everything in my queue has been run
            dispatch_release(newImages);
        });
    });

我的主要问题是使用ASIHTTPRequest startAsynchronous方法: http://allseeing-i.com/ASIHTTPRequest/使用方法#using_blocks

My main problem was using the ASIHTTPRequest startAsynchronous method: http://allseeing-i.com/ASIHTTPRequest/How-to-use#using_blocks

从本质上讲,这是造成我的瓶颈的原因,要获取2000个图像,并尝试进行2000个异步调用.如果我已经在后台,则startSynchronous方法可以正常工作,并且一次仅尝试运行1个调用.

That in essence was creating my bottleneck, 2000 images to get, 2000 asynchronous calls trying to be made. If I am already in the background the startSynchronous method works just fine and only 1 call is trying to run at a time.

这篇关于dispatch_queue_t仍在阻止主线程的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆