dispatch_queue_t still blocking main thread

前端 未结 3 936
借酒劲吻你
借酒劲吻你 2021-02-06 08:10

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.

So in my main viewDidLoadMethod I have all o

相关标签:
3条回答
  • 2021-02-06 08:47

    First, you should name the queue using reverse domain syntax, eg "com.foo.myapp.backgroundwork" - this ensures uniqueness and consistency.

    Second, you are immediately trying to release the queue you just created (and is presumably doing some work). Don't do that. Release the queue after work is done instead. The following is actually documented in the Concurrency programming guide, under "managing queue memory"

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

    edit: After re-reading the concurrency guide myself (I take my own medicine), I learned that the runtime will actually clean up a dispatch_queue that reaches 0 reference count on a background thread, so that shouldn't block your UI. It's still a bad idea to release it immediately, and instead follow the practice I demonstrated, where your task queues up it's cleanup on the main thread. So, in hindsight I'm thinking that your -getNewImages method might be responsible for blocking your UI. Can you show some code from that method so we can rule that out?

    0 讨论(0)
  • 2021-02-06 08:47

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

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

    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.

    0 讨论(0)
  • 2021-02-06 08:56

    To my understanding, ASIHTTPRequest startSynchronous requires NSRunLoop, and GCD serial queue thread doesn't have NSRunLoop. Thus, it doesn't work.

    And your code seems that GCD serial queue is not needed at all. I think GCD global queue works fine with your code. For example,

    - (void)getNewImages
    {
        dispatch_queue_t queue =
            dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0);
    
        /* snip */
        for (Manufacturer *m in self.manufacturers)
        {
            /* snip */
            ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];
            [request setCompletionBlock:^{
                /* snip */
                dispatch_async(queue, ^{
                    [responseString writeToFile:fileName atomically:YES encoding:NSUTF8StringEncoding error:nil];
                });
    
                for (NSDictionary* dict in array) {
                    /* snip */
                    ASIHTTPRequest *imageRequest = [ASIHTTPRequest requestWithURL:url];
                    [imageRequest setCompletionBlock:^{
                        /* snip */
                        dispatch_async(queue, ^{
                            [responseData writeToFile:[savePath stringByReplacingOccurrencesOfString:@"%20" withString:@" "] atomically:YES];
                        });
                    }];
                    /* snip */
                    [imageRequest startAsynchronous];
                }
                /* snip */
            }];
            /* snip */
            [request startAsynchronous];
        }
    }
    

    getNewImages method should be executed on the main thread, it requires the NSRunLoop of the main thread.

    0 讨论(0)
提交回复
热议问题