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.
Related
My aim is to cover a collectionView with a 'loading screen' which will not be hidden until all the images from a pre-fetched array of images have been loaded into cache by SDWebImage.
In my viewDidLoad I have retrieved an array of image URL's which will be used to populate a collection view. Once they are retrieved I plan on using SDWebImagePrefetcher to process the array.
so far I have the below:
let urls : [URL] = [URL(string: "https://trialwebsite.com/image1.png")!,URL(string: "https://trialwebsite.com/image2.png")!,URL(string: "https://trialwebsite.com/image3.png")!]
SDWebImagePrefetcher.shared().prefetchURLs(urls)
What I am struggling to figure out is how to use a completion block to hide the 'loading' screen once all the images have been processed.
Any help much appreciated.
You could use prefetchURLs:completed: instead of using prefetchURLs, it would has a completion block (closure since you are writing Swift) parameter that contains finishedCount and skippedCount unsigned integers:
as mentioned in the method documentation:
completionBlock
block to be called when prefetching is completed
which is seems to be what are you asking for. So it would be something like:
SDWebImagePrefetcher.shared().prefetchURLs(urls) { finishedCount, skippedCount in
// hide the 'loading' screen...
// you might need to implement your own counting logic
// to make sure that all images have been processed.
}
In Swift v4.1 & SDWebImage v3.8.2
SDWebImagePrefetcher.shared().prefetchURLs(arrayOfURLS, progress: nil, completed: { finishedCount, skippedCount in
print("Prefetch complete!")
})
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.
I want to show loader while downloading the data from the web and loading into the table and the code should be placed in common place so that we can call that from any view controller. Please help me if any one knows something on this.
You can create a UIActivityIndicatorView in the storyboard. And then can use its startAnimating and stopAnimating functions.
You can also use UIProgressView and can use its function setProgress to show how much progress is done
I'm using a UIRefreshControl to enable the pull-to-refresh gesture on a table view.
I have used the storyboard te setup the RefershControl and in my TableViewController is use the following code to bound the method to the RefeshControl:
self.refreshControl?.addTarget(self, action: Selector("getData"), forControlEvents: UIControlEvents.ValueChanged)
At the end of the getData() method I call the reloadData() method on the tableview and the stopRefreshing() method on the refreshcontrol.
This is working fine. I can pull to refresh and the table gets updated.
Next thing I want is to start the RefreshControl when the TableViewController gets loaded. To show the user that the app is getting the data.
I tried to manually start the folowing code:
self.refreshCorntrol?.beginRefreshing()
getData()
It reloads the data but the animation is not working like it should.
The table stays empty. Then when all the data is fetched the table is pulled down (like when I manually pull to refresh) en immediately pushed back up.
Anyone know if it is possible to change/fix this?
Two things could be going on.
1. UI Updates must be dispatched on the main thread.
You're updating a tableView using it's .reloadData() method, which is considered an update to the UI. This being said, you must call .reloadData() on the main thread. While this should be done automatically for you already, I have run into some cases where I need to manually move it to the main thread. This can be done using
DispatchQueue.main.async {
// Update UI ie. self.tableView.reloadData()
}
inside your function.
2. Programmatic pull refreshes don't always run for .valueChanged
It is important to call .valueChanged (or, as you have it in your code, UIControlEvents.ValueChanged) when you call the pull refresh function, so that it is aware of what you are refreshing for. When the user pull refreshes, your program already does it, in the forControlEvents segment of your refreshController declaration. However, when you call it manually from your code, it does not do this by default. Instead, you have to pass the action using sendActions. This can be done by using
self.refreshControl?.beginRefreshing()
self.refreshControl?.sendActions(for: UIControlEvents.ValueChanged)
getData()
to call the pull refresh, rather than just calling .beginRefreshing
Afterword
I ran into a similar issue a few days ago, and posted the question on Stack Overflow here (I'm providing attribution in case you can find your answer there, and because it is where I took my first solution for you from).
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
}