简体   繁体   中英

NSURLSession dataTaskWithURL very “slow”

I mean by "slow", that the callback kind of wait for the remote server to timeout to effectively fire (calling a vimeo feed, parsing it, and then displaying uiviews on the scene)

I mostly don't get how it works. I'd like my view to be populated from within the callback as soon as the response is returned

Having the code below (rubymotion, but you might get the idea):

session = NSURLSession.sharedSession
url = NSURL.URLWithString(ALBUMS_URL)
downloadTask = session.dataTaskWithURL( url, completionHandler: lambda { |data, response, error|
    # 'puts' prints the result in the console, you get it as soon as the response arrives
    puts data
    # testing with a simple view 
    v = UIView.alloc.initWithFrame(CGRectMake(0,0,@width/2,200))
    v.backgroundColor = UIColor.blackColor
    self.view.addSubview v # ==> takes forever to effectively appear on the scene
})

I ended up setting it in the main thread with the following

NSURLSession.sessionWithConfiguration(
    NSURLSessionConfiguration.defaultSessionConfiguration,
    delegate:nil,
    delegateQueue: NSOperationQueue.mainQueue
)

Something else should be used to do this kind of tasks? Is there a way to 'force' the view to be updated?

It sounds like it takes 30 seconds for the data to fully arrive. To present the data faster, you'll probably have to use a delegate, obtain the data a chunk at a time as it is received, use a parser that knows how to handle partially received data, and then add more data to your UI as you receive additional data.

Edit: Somehow when I answered this previously, I missed the fact that this only failed when not run on a main thread. As the other commenter noted, you must either start the task on the main thread or use dispatch_async inside the block so that the label changes run on the main thread. Otherwise, the UI won't get refreshed until some other code running on the main thread causes a repaint of the view in question.

The reason your UI is taking so long to update is not because the operation took so long, but it's because the NSURLSessionDataTask finishes in a background thread . As you may know, you are not supposed to be making UI changes from a background thread, only the main thread.

Your solution to put the entire URL session's callback in the main queue "solves" this problem, but not the correct way, since you are now doing network operation in the main queue, which should be little as possible for things that can be done in the background (like network operations).

To fix this, you need to do the network operations in the background thread, and then just finally call the UI-changing logic in the main thread. You can do a simple dispatch_async() call to make a block that updates the UI, like this (sorry, I'm not familiar with RubyMotion, so I'm writing this in Objective-C):

// in the callback for NSURLSessionDataTask:
NSLog(@"%@", data);

// Dispatch the UI-related logic as a block on the main-thread
dispatch_async(dispatch_get_main_queue(), ^{
    UIView *v = [[UIView alloc] initWithFrame:CGRectMake(0,0,width/2,200)];
    v.backgroundColor = [UIColor blackColor];
    [self.view addSubview:v];
});

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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