Updating label takes too long (swift) - ios

I'm beginner swift developer. I'm stucked with this weather app.I'm downloading website data and then displaying in my label.
Unfortunately this whole process takes like 10 second to update my label.
This is probably not because of the network connection as the console is updated instantly.
Thanks for suggestions.

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()) {
// update label
}
This should update your label instantly.

Previously, we would choose the dispatch method (sync vs async) and then the queue we wanted to dispatch our task to. The updated GCD reverses this order - we first choose the queue and then apply a dispatch method.
Swift 3:
Now in Swift 3 the GCD library was updated like in the following way:
DispatchQueue.main.async(execute: {
// UI Updates
})
I hope this help you.

It might be late to answer but in Swift 3 logic should be like this.
DispatchQueue.global(qos: .background).async {
// Background Thread Or Service call Or DB fetch etc
DispatchQueue.main.async {
// Run UI Updates and other logic
}}

Your code has multiple issues.
FIRST: It has strong reference cycle
Fix it by putting this in closure.
[weak weakSelf = self]
SECOND: Update UI in main thread
DispatchQueue.main.async {
//Update UI
weakSelf?.mReslut.text = ""
}

Related

Queues and Swift 3 issue [duplicate]

This question already has answers here:
How do I dispatch_sync, dispatch_async, dispatch_after, etc in Swift 3, Swift 4, and beyond?
(6 answers)
Closed 6 years ago.
Please help me to convert this line to swift 3.0:
dispatch_async(DispatchQueue.global(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0))
And what does it exactly mean? Something like: do the code in brackets in the main queue?
Thanks in advance.
ps. This line of code was taken from apple's code to work with core data
In Swift 3 You can write like this
DispatchQueue.global(qos: .background).async {
}
It means what every the code written in between the bracket will perform in the background. and if you want to make any changes in this background thread you have to switch to the main thread. by writing the block below.
dispatch_async(dispatch_get_main_queue()) {
// Your code for UI Changes.
}
EDIT: Swift 3
DispatchQueue.main.async {
}
One of the most common task in Grand Central Dispatch (GDC) pattern is performed work on a global background queue and update the UI on the main queue as soon as the work is done.The new API looks like this:
DispatchQueue.global(attributes: [.qosDefault]).async {
// Background thread
DispatchQueue.main.async(execute: {
// UI Updates
})
}
Queues now take attributes on init. This is a Swift optionSet and can include queue options such as serial vs concurrent, memory and activity management option and the quality of service (.default, .userInteractive, .userInitiated, .utility and .background).
New changes:
DISPATCH_QUEUE_PRIORITY_HIGH: -> .userInitiated
DISPATCH_QUEUE_PRIORITY_DEFAULT: -> .default
DISPATCH_QUEUE_PRIORITY_LOW: -> .utility
DISPATCH_QUEUE_PRIORITY_BACKGROUND: -> .background
if you want to learn more about, this is a good talk https://developer.apple.com/videos/play/wwdc2016/720/

asynchronous Swift function taking long time to update label [duplicate]

I'm beginner swift developer. I'm stucked with this weather app.I'm downloading website data and then displaying in my label.
Unfortunately this whole process takes like 10 second to update my label.
This is probably not because of the network connection as the console is updated instantly.
Thanks for suggestions.
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()) {
// update label
}
This should update your label instantly.
Previously, we would choose the dispatch method (sync vs async) and then the queue we wanted to dispatch our task to. The updated GCD reverses this order - we first choose the queue and then apply a dispatch method.
Swift 3:
Now in Swift 3 the GCD library was updated like in the following way:
DispatchQueue.main.async(execute: {
// UI Updates
})
I hope this help you.
It might be late to answer but in Swift 3 logic should be like this.
DispatchQueue.global(qos: .background).async {
// Background Thread Or Service call Or DB fetch etc
DispatchQueue.main.async {
// Run UI Updates and other logic
}}
Your code has multiple issues.
FIRST: It has strong reference cycle
Fix it by putting this in closure.
[weak weakSelf = self]
SECOND: Update UI in main thread
DispatchQueue.main.async {
//Update UI
weakSelf?.mReslut.text = ""
}

Understanding why I need to dispatch back to main thread

I just wanted to clear up something that feels a bit unclear for me. Consider the following code that executes a closure asynchronously:
func fetchImage(completion: UIImage? -> ()) {
dispatch_async(dispatch_get_global_queue(QOS_CLASS_BACKGROUND, 0)) {
// fetch the image data over the internet
// ... assume I got the data
let image = UIImage(data: data)
dispatch_async(dispatch_get_main_queue()) {
completion(image)
}
}
}
To my understanding, the reason we need to dispatch back to the main thread is because it would otherwise take longer to call the completion closure to give back the image.
However, I feel that perspective is a bit cheesy. For example, I'd also like to create a isLoading property that would be used to prevent multiple network calls from happening at the same time:
func fetchImage(completion: UIImage? -> ()) {
// if isLoading is true, then don't continue getting the image because I want only 1 network operation to be running at 1 time.
if isLoading {
completion(nil)
return
}
isLoading = true
dispatch_async(dispatch_get_global_queue(QOS_CLASS_BACKGROUND, 0)) {
let image = UIImage(data: data)
// image creation is complete. Set isLoading to false to allow new fetches
self.isLoading = false
dispatch_async(dispatch_get_main_queue()) {
completion(image)
}
}
}
For this above snippet, my question is - Should I place self.isLoading = false in the dispatch block to the main queue? Or is it insignificant?
All advice appreciated!
It isn't that "it would otherwise take longer", it is that all updates to the UI must be performed on the main queue to prevent corruption that may occur from concurrent updates to the autolayout environment or other UI datastructures that aren't thread-safe.
In prior versions of iOS a common side effect of not updating the UI on the main thread was a delay in that upgrade appearing, however as of iOS 9 you will get an exception.
In terms of your question, it is best that your code behaves consistently. I.e. Either always dispatch the completion handler on the main queue or never do so. This will allow the programmer who is writing the completion block to know whether they need to dispatch UI updates or not.
It is probably best to set isLoading to false as soon as the load has finished, so outside the dispatch_async is best.
Given that your function is retrieving a UIImage there is a good chance that the caller will be updating the UI, so it is probably 'nice' to dispatch the completion handler on the main thread.
To fetch the image from internet in background you simply need to do an async request, you don't need to do it in the background queue as you are doing now.
On the main thread you basically need to do all that things about UI manipulation, because it always run on main thread. This is the important part.
So, the request completion block (the one you'll use to fetch the image) is executed in background (since it is async) and here, inside the block, you need to get the main thread to set the image for the UIImageView for instance.
Other properties than the ones directly related to UI element doesn't needs to be on the main thread as far as I know and I have never had a problem this way.

background processing a difficult task on viewDidLoad in swift

I am currently making an app which initiates a very long task on the viewDidLoad method. The nature of it is stopping the view from loading at all for extended periods of time and sometimes causes the app to crash. As such, I need to be able to process this particular task in the background so that the view can load instantly and then, in the background, complete the task and update the view when it is done. Does anybody know how to do this?
Try to use GCD similar to this:
let backgroundQueue = dispatch_get_global_queue(CLong(DISPATCH_QUEUE_PRIORITY_HIGH), 0)
dispatch_async(backgroundQueue) {
// Do your stuff on global queue.
dispatch_async(dispatch_get_main_queue(), { () -> Void in
// After finish update UI on main queue.
})
}
Or you can use NSOperationQueue. At WWDC 2105 was very nice talk about it. https://developer.apple.com/videos/wwdc/2015/?id=226

dispatch_async on main_queue?

I have seen this code snippet:
dispatch_async(dispatch_get_main_queue(), ^{
[self doSomeNetworkStuff];
});
This doesn't look like making much sense to me.
EDIT: To clarify the conditions of my question:
The call to dispatch_async is performed from the main thread.
The sent message doSomeNetworkStuff is the heavy lifting worker task.
... and is not only the UI-updating task.
Dispatch, sure, but using the main queue would just pull the dispatched task back to the ui thread and block it.
Please, am I missing something?
Thanks.
dispatch_async lets your app run tasks on many queues, so you can increase performance.
But everything that interacts with the UI must be run on the main thread.
You can run other tasks that don't relate to the UI outside the main thread to increase performance.
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
//Add some method process in global queue - normal for data processing
dispatch_async(dispatch_get_main_queue(), ^(){
//Add method, task you want perform on mainQueue
//Control UIView, IBOutlet all here
});
//Add some method process in global queue - normal for data processing
});
Swift 3:
DispatchQueue.global(attributes: .qosBackground).async {
print("This is run on the background queue")
DispatchQueue.main.async {
print("This is run on the main queue, after the previous code in outer block")
}
}
when you want to do some Webservicecall or something you dispatch a async call like this below:
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0),^{
//Call your webservice here , your app will not freeze at all
});
Now, suppose you want to update or push a ViewController from your dispatched thread, if you directly push viewcontroller from this, app will or may get crashed,as such UI updates should be done in main thread of app,below is the answer for this then.
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0),^{
//Call your webservice here , your app will not freeze at all
//To update UIFrom dispatched Thread:
dispatch_async(dispatch_get_main_queue,^{
//Push view controller here
});
});
for detail visit : blackberrymastercracks.blogspot.in
It depends from where this code is being called. Means if its calling from main queue then it doesn't make sense. (Note: it will not cause a crash but it will just add a task in main queue ).
If this code is written in background thread then this is a converging point for the application. Like you are getting data from web service in background thread then wants to update it on UI then you can call it.
-(void) backgroundThreadFunction {
//Some stuff on background thread.
dispatch_async(dispatch_get_main_queue(), ^{
//Wants to update UI or perform any task on main thread.
[self doSomeNetworkStuff];
});
}
You can find more details over apple documentation https://developer.apple.com/library/ios/documentation/General/Conceptual/ConcurrencyProgrammingGuide/OperationQueues/OperationQueues.html
or from this answer also https://stackoverflow.com/a/19822753/505735
Do post me if its still unclear. I will write a detailed answer.
You'll usually see that syntax inside of another dispatch_async call that runs on a background thread. This is because all updates to the UI should happen on the main thread, not in the background.
I lost track of this question, but as it still gets traction, I'll post an answer to this (using swift)
Assumptions: I do know that UI work has to be done on the main thread.
//
// We are on the main thread here.
// The following will schedule the closure on the main thread after ALL other
// routines currently scheduled on the main thread are done.
//
DispatchQueue.main.async {
//
// So here we are back on the main thread AFTER all routines on the main
// thread have completed.
//
// If the following call does NOT dispatch onto a background thread
// it will block the UI and it was really bad programming.
//
// Thus, for now and for the benefit of the doubt, let's assume
// `doSomeNetworkStuff()` DOES dispatch to a background thread.
//
// This can only make sense if the the func `doSomeNetworkStuff()`
// relies on results of code paths following this current
// `DispatchQueue.main.async(... we are here ...)`.
//
// If `doSomeNetworkStuff()` does NOT depend on any other code paths:
// Why not directly scheduling it directly on a background thread?
// Which is unnecessary, as as stated above it MUST dispatch on to the
// background anyways.
//
// Moreover, there is few possibility that `doSomeNetworkStuff()` does
// depend on other codepaths, because `self` is already captured by
// the closure.
//
self.doSomeNetworkStuff()
}
Taking all this together IMHO the original code does not make very much sense. It could be replaced with:
// We are on the main thread here
self.doSomeNetworkStuff()
The original async dispatch onto the main thread to then dispatch to background should be wasteful and confusing (obviously).
Unfortunately I am not in the position anymore to try this out with the original code base.
Am I missing an idea here?

Resources