Swift : collectionView takes too long to display - ios

I am developing an iOS application in Swift.
I display data from database inside a collectionview but it takes too much time to appear on screen.
Surely a thread problem because on Xcode console, I can see data being displayed 20 seconds before it appears on the screen. Here is my code :
https://github.com/ProjetCedibo/projet/blob/master/Projet-L3-master/appli/SJEPG/SJEPG/CenterViewController.swift
How can I make the collectionView being displayed faster ?

If this happens, it means you are making UI changes from a thread other than the main thread. Try this:
func refresh() {
dispatch_async(dispatch_get_main_queue(), {
self.eventsCollection.reloadData()
})
}

What happens is that code is probably run on a secondary thread. Any UI changes you make should be made on the main thread. So try this:
dispatch_async(dispatch_get_main_queue()){
// reload your collection view here
})

In addition to #StefanArentz answer
For Swift 3:
DispatchQueue.main.async {
// code to reload collection view
}

Related

How to quickly open a view controller without executing it's processes?

I have to show various folders which contain a heavy amount of images and videos , but when I click on the folder it takes few seconds to load which seems like it's lagging or hanging ...
I wanna open view controller first and then show the process of loading....
How to do that ???
you can load data in background like this
DispatchQueue.global(qos: .background).async {
// load data here
}
after that need to load UI in main thread
DispatchQueue.main.sync {
// show data here
}
you can solve this problem by using SDWebImage for problem of photos or images loading...
myimageview.sd_setImage(with: imageURL, placeholderImage: UIImage(named: "empty_image_icon"))
//imageURL is URL of image.
//empty_image_icon id the default image which will show during process.
Fetch data in viewWillAppear() method not in viewDidLoad() method.
You can fetch your data/media in viewDidAppear() method and start animating your loading indicator in viewDidLoad() method.
If you load data in viewWillAppear() than your viewController take a time with few second.
You can call your fetching data function after your view created. The viewDidAppear() method is working after your view created but also, this method works whenever the view you create is visible on the screen so it could not be the best solution for every case. It means that, your data could be fetching unnecessarily. For example, viewDidAppear() method is working whenever you change your view controller and come back that screen again or switch your application or your app comes foreground.
Therefore, using dispatchQueue or SDWebImage library could be your answer.

Swift - Force view to load data after appearing

Heyho,
i got a little problem with two of my view controllers.
They are both collection view controllers.
My problem is, if i click on the button to open the second view it lags and the transition is not liquid. The reason for this lag is the bunch of data the view loads for the collection view(around 400 photos and strings).
Maybe someone of you got a idea how i could defeat this loading inhibition. If you need more information --> just ask.
An easy way to fix that is to load you data in a background thread and reload your collection view (in the UI thread) when it's done:
DispatchQueue.global(qos: .background).async {
// load your data here
DispatchQueue.main.async {
// reload your collection view here:
self.collectionView.reloadData()
}
}
you can use this method to achieve the required result.
override func viewDidLayoutSubviews() {
// Configure the views
}
On the other hand, you have self.view.setNeedsLayout() and self.view.layoutIfNeeded(). Find the one which suits you.

How can I tell when a UITableView has finished reloading itself [duplicate]

This question already has answers here:
How can I tell when UITableView has completed ReloadData?
(18 answers)
Closed 5 years ago.
Calling tableView.reloadData() seems to initiate the reload on a different thread. If I immediately try to select a cell I've added to my data structure, it may not have been reloaded by the TableView yet. Is there a way to tell when the TableView has completed the reloadData() process. My actual code is:
DispatchQueue.main.async {
self.tableView.reloadData()
self.selectNode(node: newNode)
}
Where selectNode is my function to locate the TableViewCell displaying that node. Frequently, it fails because TableView hasn't re-displayed it yet. I can "brute force" a solution by inserting a wait loop that checks to see if TableView has requested all my rows since the reload, but I had hoped there was a more elegant solution. I'm also uncomfortable with wait loops in general.
I wanted to share the solution I found to the problem, as well as what it implies about how tableView.reloadData works. First, here's the code that I finally arrived at that works:
func addNewItem() {
// here we create the kind of item the user chose
//ending with this
tableView.reloadData()
queueCheckForDone()
}
func queueCheckForDone() {
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + .milliseconds(1), execute: {
self.checkForDone()
})
}
func checkForDone() {
if items[items.count-1].viewCell != nil { // has last view cell been created
self.selectItem(item: addedItem)
} else {
queueCheckForDone()
}
}
The issue was that immediately after the reloadData, I wished to select the cell that I had just been added. But, it wasn't there immediately after the call, because the tableView hadn't finished loading. reloadData wants to run on the main thread, and my code, an event handler, was blocking it by being on the main thread. As soon as I relinquished the thread to wait, for even a millisecond, reloadData seized the thread and reloaded the whole table(> 250ms). When I finally got control again, the cell I was looking for was always there, and so I never executed the else clause of the checkForDone test.

Long delays displaying UIImageView loaded from local file?

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.imgur.com/sa5qfRM.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...

Swift Xcode6 UIActivityIndicatorView Slow to display

How do I get the UIActivityIndicatorView to display first, then execute other code?
I've experimented with using sleep, and it works but it doesn't "feel" right and adds an extra second to processing a bunch of core data stuff. I've also tried dispatching it to the main thread which only works some of the time. (I'm guessing when the rest of the block is executed outside of the main thread).
Ideally as soon as a user touches the button the instance of the UIActivityIndicatorView would display (which seems to happen where I've used it in other apps by itself or with other minimal processing).
Details: I have an IBAction connected to a button that executes a bunch of core data stuff, sometimes including images, that takes between 1 - 3 seconds to finish. When it finishes it dismisses the view controller. The view controller where this is executed is presented as a modal over current context.
Here is a code snippet:
// get the background queue
let bg_queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)
dispatch_async(bg_queue, {
// long running code here...
dispatch_async(dispatch_get_main_queue(), {
self.activityIndicator.stopAnimating()
})
})

Resources