Unable to run JSContext in background thread - ios

Here I'm initiating the JS call from swift and based on the results app UI gets updated. Since this method is time taking process it freezes the app for a few seconds and becomes normal. We can understand it's running in the main thread so blocked the UI. I have tried to run it in the background using the below code and it doesn't work.
DispatchQueue.global(qos: .background).async {
let fn = engineJSContext?.objectForKeyedSubscript("jsMethodName")
let val = fn?.call(withArguments: [params1, params2])
}
As per the below document, we can run it from any thread, but I'm facing a problem on the background thread. Any help on this, please!
https://developer.apple.com/documentation/javascriptcore/jsvirtualmachine

Related

Swift: Multipeer Connectivity + UI Update

My application is to communicate between about 5 iPads and update according to the data received through multipeer connectivity framework.
One of the iPad do the followings: It get its current location and send it to other peers. The peers update the UI according to the location received.
I found that there is a problem that when the iPad need to send the packet to the others, it cause its UI did not update immediately. The UI events stuck until it finished sending the packet. Since the location keep on updated, all these events fired continuously.
I have tried to place the send packet in a thread:
let bgQueue = DispatchQueue(label: "hk.edu.polyu.isurf.sendqueue", qos: .utility, attributes: .concurrent)
And then put the code for sending packet inside this bgQueue:
func sendPacket {
bgQueue.async {
// create packet, and send
}
}
My location update code will cause this:
func receiveLocation() {
sendPacket()
updateUI()
}
How can I improve the efficiency? The UI basically cannot update now, it is of serious "lagging".
I have tried to change the type of the bgQueue, but no improvement.
Thank you.
You should make sure that your UI is being updated on the main queue.
If your trying to update UI in the session didRecieve function, this is a function that runs in the background. This means any UI changes made inside of it need to be put inside a Dispatch to the main queue so its updates take place immediately.
DispatchQueue.main.async
{
// UI updates go here
}

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

Updating label takes too long (swift)

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 = ""
}

Resources