In my Swift code I have a process that's running on a secondary thread. In it there is a recursive method that I would like to pause every once in a while for a second or less. I was hoping I could just say sleep(0.5) but of course that would be too easy. BTW, anyone wanting to tell me that pausing is bad needn't bother. I'm aware of the various issues.
The process is kicked off with DispatchQueue.global(qos: .utility).async { }
It makes a callback for some UI calls which are done in a DispatchQueue.main.async { }
Does anyone have a nice little way to suspend and resume a thread at a specific point in the code like:
func myMethod() {
for n in 1...100 {
do some stuff
callback(parameters)
based on some logic possibly Thread.pause
recursively call myMethod()
}
}
My recursion works just fine but I just want to slow it down occasionally. I assume with some refactoring I could achieve the same effect but it would be so simple to just insert a quick little inline pause.
I would like to credit Rob with actually answering my question by saying to use Thread.sleep. I tried that but it didn't seem to work at first. However, as I told him, I kept trying and eventually I got it to work. Not sure exactly which "comma" or "period" actually did the trick because I tried so many variations. Bottom line is that I used usleep to get a finer resolution on the pause since sleep has to be integer seconds and I wanted less than a second. Despite the warnings about using pauses in the first place or recursing from inside a for-loop, the following code works exactly as needed:
view controller
object.callback = { () -> () in
DispatchQueue.main.async {
self.otherView.setSomeUI()
}
}
DispatchQueue.global(qos: .background).async() {
if self.object.method() { print("done") }
else { print("error") }
}
object
private func method() -> Bool
{
if conditionA { return true } // done
if conditionB {
if method() { return true }
} else {
for n in 1...N {
if test() {
self.callback?()
usleep(x)
if self.method() {
return true
} else {
self.callback?()
}
}
}
}
return false
}
Related
I'm looping through a table's rows, for each of them I'm doing a couple of async calls like fetching data from API, copying files, running shell script... How do I wait for the result until going to the next one.
Also I'm new to Swift, not sure if this is the best way to handle a group of async tasks. Should I use concurrency in this case ?
tableView.selectedRowIndexes.forEach { row in
myData.fetch(url: urlList[row]) { res in
self.anotherAsyncCall(res) { data in
//continue to deal with next row now
}
}
}
If you really want to do this sequentially, the easiest way is to perform your tasks recursively, actually invoking the next task in the completion handler of the prior one:
processNext(in: tableView.selectedRowIndexes) {
// do something when they're all done
}
Where:
func processNext(in rows: [Int], completion: #escaping () -> Void) {
guard let row = rows.first else {
completion()
return
}
myData.fetch(url: urlList[row]) { res in
self.anotherAsyncCall(res) { data in
//continue to deal with next row now
self.processNext(in: Array(rows.dropFirst()), completion: completion)
}
}
}
But I agree with GoodSp33d that the other approach is to wrap this asynchronous process in a custom, asynchronous, Operation subclass.
But this begs the question why you want to do these sequentially. You will pay a significant performance penalty because of the inherent network latency for each request. So the alternative is to let them run concurrently, and use dispatch group to know when they're done:
let group = DispatchGroup()
tableView.selectedRowIndexes.forEach { row in
group.enter()
myData.fetch(url: urlList[row]) { res in
self.anotherAsyncCall(res) { data in
//continue to deal with next row now
group.leave()
}
}
}
group.notify(queue: .main) {
// do something when they're all done
}
Whether you can run these concurrently (or to what degree) is a function of what you're doing inside various asynchronous methods. But I would suggest you think hard about making this work concurrently, as the performance is likely to be much better.
If you are using some promise library, just use the all function.
Here is some Document about promise.all()
And PromiseKit use when instead,
you can read about the faq and the tutorial about when for more information.
If you want to do that without any promise library, here is the pseudocode:
var results = []
rows.forEach {row in
fetch(row) {res in
results.push(res)
if(results.length == rows.length) {
// do something using the results here
}
}
}
In Swift, if I'm inside of a closure, that is itself inside of another function, is there a way to exit out of the function itself?
Here's an example of what this might look like using closures from the GCDKit library.
func test() {
GCDQueue.Default.async {
print("Print me!")
return //Is there a statement that does this?
}.notify(.Main) {
print("Never print me.")
}
}
No there is not. Closures run in self-contained environments. For all you know, by the time that closure is executed, the thread on which test() was called is no longer executing the test() method.
Let's consider a simpler version that doesn't include any third-party libraries, extra queues, or other complexity. We'll just create a closure and immediately execute it.
func dothing(andPrint shouldPrint: Bool) {
let closure = {
guard shouldPrint else { return }
print("I printed!")
}
closure()
print("did it return?")
}
dothing(andPrint: false) // Prints "did it return?"
The return here exits the closure, not dothing. Since closure could be passed to some other function, or stored in a property and executed at some later time (possibly on a different queue as in your example), there's no way for the return to exit anything beyond itself. Consider if we were to refactor the creation of the closure into its own function:
func fetchClosure(andPrint shouldPrint: Bool) -> () -> Void {
return {
guard shouldPrint else { return }
print("I printed!")
}
}
func dothing(andPrint shouldPrint: Bool) {
let closure = fetchClosure(andPrint: shouldPrint)
closure()
print("did it return?")
}
dothing(andPrint: false) // Prints "did it return?"
It shouldn't be surprising this has the same behavior (otherwise this wouldn't be a simple refactor). Now imagine how it would (or even could) work if return behaved any other way.
Your example is just a much more complicated version of the same thing. return exits the closure.
I have two tasks : task1 and task2. I want to execute task2 after task1 finishes.
let globalQueueDefault = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0)
dispatch_sync(globalQueueDefault){
self.activityIndicatorView.hidden = false
self.activityIndicatorView.startAnimating()
task1()
sleep(6)
dispatch_sync(globalQueueDefault) { () -> Void in
task2()
}
}
I searched in internet, I find NSLock,NSConditionLock and objc_sync_enter...I have try them, but it doesn't work...
let lock = NSLock()
let globalQueueDefault = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0)
dispatch_sync(globalQueueDefault){
self.activityIndicatorView.hidden = false
self.activityIndicatorView.startAnimating()
self.lock.lock()
task1()
self.lock.unlock()
sleep(6)
dispatch_sync(globalQueueDefault) { () -> Void in
self.lock.lock()
task2()
self.lock.unlock()
}
}
I also tried NSConditionLock and objc_sync_enter...It doesn't work. How I can use lock in swift ? Could you give me a example base on my code? Thank you.
PS: I don't want to use callback here...because I have tried it, I think multithread is more closer to my answer, Thank you.
I'm going out on a limp and making some guesses about your program structures. The first problem with your code is that it's trying to access a view on a background thread. GUI elements should always be accessed on the main thread. The second problem is sleep: don't use it to write concurrent code. It makes assumptions about how the asynchronous task is going take. You should treat that time as unknown and use a sync pattern or a call back.
Since you mentioned that task1() download JSON, it's likely asynchronous. Here's how I'd do it:
func task1(finish: () -> Void) {
// Set up your connection to the website
let task = NSURLSession.sharedSession().dataTaskWithRequest(request) {
// Handle the response, parse the json, etc
...
// Now call the completion handler
finish()
}
}
func task2() {
// Do whatever here
}
// In the function that triggers the JSON download
func downloadJSON() {
self.activityIndicatorView.hidden = false
self.activityIndicatorView.startAnimating()
task1(task2)
}
I'm trying to wait for Parse async functions in Swift to reload my UITableView
I'm not sure if Completion Handler is useful in this case. or Dispatch Async.
I'm really confused ! Can someone help out with this
var posts = [PFObject]()
for post in posts {
post.fetchInBackground()
}
tableView.reloadData() // I want to execute that when the async functions have finished execution
You want to use fetchAllInBackground:Block I've had issues launching a bunch of parse calls in a loop where it will take a lot longer to return all of them than expected.
fetch documentation
It should look something like this:
PFObject.fetchAllInBackground(posts, block: { (complete, error) in
if (error == nil && complete) {
self.tableView.reloadData()
}
})
One thing to note is that in your example posts are empty and a generic PFObject. I'm assuming this is just for the example. Otherwise if you want to get all posts in Parse (as opposed to updating current ones) you will want to use PFQuery instead of fetching. query documentation
You need to use fetchInBackgroundWithBlock. Alternatively, if you want to wait until all have loaded and then update the UI, use PFObject's +fetchAllInBackground:block:. Note that this is a class method, and would therefore be called as PFObject.fetchAllInBackground(.... See documentation here.
Either way, because you're running in a background thread, you must update the UI on the main thread. This is normally done using dispatch_async.
The other thing to watch out for is if you run fetchInBackgroundWithBlock in a loop and collect all the results in an array, arrays are not thread safe. You will have to use something like dispatch_barrier or your own synchronous queue to synchronise access to the array. Code for the second option is below:
// Declared once and shared by each call (set your own name)...
let queue = dispatch_queue_create("my.own.queue", nil)
// For each call...
dispatch_sync(queue) {
self.myArray.append(myElement)
}
Here's a little class I made to help with coordination of asynchronous processes:
class CompletionBlock
{
var completionCode:()->()
init?(_ execute:()->() )
{ completionCode = execute }
func deferred() {}
deinit
{ completionCode() }
}
The trick is to create an instance of CompletionBlock with the code you want to execute after the last asynchronous block and make a reference to the object inside the closures.
let reloadTable = CompletionBlock({ self.tableView.reloadData() })
var posts = [PFObject]()
for post in posts
{
post.fetchInBackground(){ reloadTable.deferred() }
}
The object will remain "alive" until the last capture goes out of scope. Then the object itself will go out of scope and its deinit will be called executing your finalization code at that point.
Here is an example of using fetchInBackgroundWithBlock which reloads a tableView upon completion
var myArray = [String]()
func fetchData() {
let userQuery: PFQuery = PFUser.query()!
userQuery.findObjectsInBackgroundWithBlock({
(users, error) -> Void in
var userData = users!
if error == nil {
if userData.count >= 1 {
for i in 0...users!.count-1 {
self.myArray.append(userData[i].valueForKey("dataColumnInParse") as! String)
}
}
self.tableView.reloadData()
} else {
print(error)
}
})
}
My example is a query on the user class but you get the idea...
I have experimented a bit with the blocks and they seem to get called on the main thread, which means that any UI changes can be made there. The code I have used to test looks something like this:
func reloadPosts() {
PFObject.fetchAllIfNeededInBackground(posts) {
[unowned self] (result, error) in
if let err = error {
self.displayError(err)
}
self.tableView.reloadData()
}
}
if you are in doubt about whether or not the block is called on the main thread you can use the NSThread class to check for this
print(NSThread.currentThread().isMainThread)
And if you want it to be bulletproof you can wrap your reloadData inside dispatch_block_tto ensure it is on the main thread
Edit:
The documentation doesn't state anywhere if the block is executed on the main thread, but the source code is pretty clear that it does
+ (void)fetchAllIfNeededInBackground:(NSArray *)objects block:(PFArrayResultBlock)block {
[[self fetchAllIfNeededInBackground:objects] thenCallBackOnMainThreadAsync:block];
}
The answers I've seen so far (1, 2, 3) recommend using GCD's dispatch_once thus:
var token: dispatch_once_t = 0
func test() {
dispatch_once(&token) {
print("This is printed only on the first call to test()")
}
print("This is printed for each call to test()")
}
test()
Output:
This is printed only on the first call to test()
This is printed for each call to test()
But wait a minute. token is a variable, so I could easily do this:
var token: dispatch_once_t = 0
func test() {
dispatch_once(&token) {
print("This is printed only on the first call to test()")
}
print("This is printed for each call to test()")
}
test()
token = 0
test()
Output:
This is printed only on the first call to test()
This is printed for each call to test()
This is printed only on the first call to test()
This is printed for each call to test()
So dispatch_once is of no use if we I can change the value of token! And turning token into a constant is not straightforward as it needs to of type UnsafeMutablePointer<dispatch_once_t>.
So should we give up on dispatch_once in Swift? Is there a safer way to execute code just once?
A man went to the doctor, and said "Doctor, it hurts when I stamp on my foot". The doctor replied, "So stop doing it".
If you deliberately alter your dispatch token, then yes - you'll be able to execute the code twice. But if you work around the logic designed to prevent multiple execution in any way, you'll be able to do it. dispatch_once is still the best method to ensure code is only executed once, as it handles all the (very) complex corner cases around initialisation and race conditions that a simple boolean won't cover.
If you're worried that someone might accidentally reset the token, you can wrap it up in a method and make it as obvious as it can be what the consequences are. Something like the following will scope the token to the method, and prevent anyone from changing it without serious effort:
func willRunOnce() -> () {
struct TokenContainer {
static var token : dispatch_once_t = 0
}
dispatch_once(&TokenContainer.token) {
print("This is printed only on the first call")
}
}
Static properties initialized by a closure are run lazily and at most once, so this prints only once, in spite of being called twice:
/*
run like:
swift once.swift
swift once.swift run
to see both cases
*/
class Once {
static let run: Void = {
print("Behold! \(__FUNCTION__) runs!")
return ()
}()
}
if Process.arguments.indexOf("run") != nil {
let _ = Once.run
let _ = Once.run
print("Called twice, but only printed \"Behold\" once, as desired.")
} else {
print("Note how it's run lazily, so you won't see the \"Behold\" text now.")
}
Example runs:
~/W/WhenDoesStaticDefaultRun> swift once.swift
Note how it's run lazily, so you won't see the "Behold" text now.
~/W/WhenDoesStaticDefaultRun> swift once.swift run
Behold! Once runs!
Called twice, but only printed "Behold" once, as desired.
I think the best approach is to just construct resources lazily as needed. Swift makes this easy.
There are several options. As already mentioned, you can initialize a static property within a type using a closure.
However, the simplest option is to define a global variable (or constant) and initialize it with a closure then reference that variable anywhere the initialization code is required to have happened once:
let resourceInit : Void = {
print("doing once...")
// do something once
}()
Another option is to wrap the type within a function so it reads better when calling. For example:
func doOnce() {
struct Resource {
static var resourceInit : Void = {
print("doing something once...")
}()
}
let _ = Resource.resourceInit
}
You can do variations on this as needed. For example, instead of using the type internal to the function, you can use a private global and internal or public function as needed.
However, I think the best approach is just to determine what resources you need to initialize and create them lazily as global or static properties.
For anyone who stumbles on this thread... We ran into a similar situation at Thumbtack and came up with this: https://www.github.com/thumbtack/Swift-RunOnce. Essentially, it lets you write the following
func viewDidAppear(animated: Bool) {
super.viewDidAppear(animated: Bool)
runOnce {
// One-time code
}
}
I also wrote a blog post explaining how the code works, and explaining why we felt it was worth adding to our codebase.
I found this while searching for something similar: Run code once per app install. The above solutions only work within each app run. If you want to run something once across app launches, do this:
func runOnce() {
if UserDefaults.standard.object(forKey: "run_once_key") == nil {
UserDefaults.standard.set(true, forKey: "run_once_key")
/* run once code */
} else {
/* already ran one time */
}
}
If the app is deleted and re-installed, this will reset.
Use NSUbiquitousKeyValueStore for tracking a value across installs and devices as long as user using same appleID.