0

I see questions regarding long delays in displaying UIImageViews after downloading, but my question involves long delays when reading from local storage.

After archiving my hierarchy of UIImageViews to a local file (as per narohi's answer in How to output a view hierarchy & contents to file? ), I find that if I want to reload them, it takes 5 to 20 seconds for the views to actually appear on screen, despite my setting setNeedsDiplay() on the main view and all the subviews.

I can immediately query the data contained in the custom subclasses of UIView that get loaded -- showing that NSKeyedUnarchiver and all the NS-decoding and all the init()'s have completed -- however the images just don't appear on the screen for a long time. Surely the next redraw cycle is shorter than 5-20 seconds...?

It seems odd that images from PhotoLibrary appear instantly, but anything loaded from local file storage using NSKeyedUnarchiver takes "forever."

What's going on here, and how can I speed this up?

.

.

To be explicit, the relevant part of my Swift code looks like this:

let view = NSKeyedUnarchiver.unarchiveObjectWithFile(path) as! UIView!
if (nil == view) {
   return
}
myMainView.addSubview(view)
view.setNeedsDisplay()
// now do things with the data in view ...which all works fine

I find that, even if I add something like...

for subview in view.subviews {
    subview.setNeedsDisplay()
}

...it doesn't speed up the operations.

We are not talking huge datasets either, it could be just a single imageview that's being reloaded.

Now, I do also notice these delays occurring when downloading from the internet using a downloader like the one shown in https://stackoverflow.com/a/28221670/4259243 ...but I have the downloader print a completion message after not only the download but when the (synchronous operation) data.writeToFile() is complete (and before I try to load it using NSKeyedUnarchiver), so this indicates that the delay in UIImageView redraws is NOT because the download is still commencing....and like I say, you can query the properties of the data and it's all in memory, just not displaying on the screen.

UPDATE: As per comments, I have enclosed the needsDisplay code in dispatch_async as per Leo Dabus's advice, and done some Time Profiling as per Paulw11's. Link to Time Profiling results is here: https://i.stack.imgur.com/YLri1.png I stopped the profiling immediately after the image appeared on the screen at around 1:00, but it was actually 'loaded' during the bump around 20s. During that period it seems like nothing's happening...? The code is literally just waiting around for a while?

Just to be clear how I'm implementing the dispatch_async, see here:

func addViewToMainView(path: String) {
    let view = NSKeyedUnarchiver.unarchiveObjectWithFile(path) as! UIView!
    if (nil == view) {
       return
    }
    dispatch_async(dispatch_get_main_queue(), {
       self.myMainView.addSubview(view)
       view.setNeedsDisplay()
       self.myMainView.setNeedsDisplay()
    })
}

...Since posting this I've found a few posts where people are complaining about how slow NSKeyedUnarchiver is. Could it just be that? If so, :-(.

SECOND UPDATE: Ahh, the "let view = " needs to be in the dispatch_async. In fact, if you just put the whole thing in the dispatch_async, it works beautifully! so...

func addViewToMainView(path: String) {
    dispatch_async(dispatch_get_main_queue(), {
        let view = NSKeyedUnarchiver.unarchiveObjectWithFile(path) as! UIView!
        if (nil == view) {
           return
        }

       self.myMainView.addSubview(view)
       view.setNeedsDisplay()
       self.myMainView.setNeedsDisplay()
    })
}

This works instantly. Wow.. Credit to Leo Dabus. Leaving this here for others...

Community
  • 1
  • 1
sh37211
  • 1,411
  • 1
  • 17
  • 39
  • 1
    You need to update the UI from the main thread. all you need is to use dispatch async from the main queue – Leo Dabus Sep 07 '15 at 21:29
  • http://stackoverflow.com/a/27712427/2303865 – Leo Dabus Sep 07 '15 at 21:30
  • Thanks, uh, I must be dense: how is pushing the UI update to asynchronous operation (which seems to be what's happening anyway) supposed to help? Just as an exercise, I wrapped the addSubview and setNeedsDisplay() in dispatch_async, but it still took 19 seconds to update. `dispatch_async(dispatch_get_main_queue(), { self.myMainView.addSubview(view) view.setNeedsDisplay() self.myMainView.setNeedsDisplay() })` ...No effect. – sh37211 Sep 07 '15 at 21:54
  • You should run your app with the time profiler instruments tool and see where the time is being spent. – Paulw11 Sep 07 '15 at 22:07
  • Where do you create your view? Thats where you need to use dispatch async. – Leo Dabus Sep 07 '15 at 23:00
  • Thanks guys, I updated & added new content to the question to address Time Profiling and show using dispatch_async where I create the view. – sh37211 Sep 07 '15 at 23:22
  • Boom. Sorry, Leo, I did not understand that the view creation itself needs to be in the dispatch_async. Now it works immediately! Thanks! Will make one final update to show new code. If you want to make your comment into an answer, I'll pick it! – sh37211 Sep 07 '15 at 23:34

0 Answers0