Launch function at the end of another swift - ios

I need to launch the funcion "caricaImmagine" after the function "caricaLavori". In the code is clear that caricaImmagine need that caricaLavori finish to append item to an array.
I've tried this but I don't know how to implement it.
Here's the "newMethod" (called in viewWillAppear):
func newMethod(){
print("login: \(login)")
let userFetch = NSFetchRequest<NSFetchRequestResult>(entityName: "UserEntity")
do {
fetchUsers = try moc.fetch(userFetch) as! [User]
} catch {
fatalError("Failed to fetch person: \(error)")
}
do{
let users = try moc.fetch(userFetch)
if(users.count > 0){
print("utente connesso")
tableview.delegate = self
tableview.dataSource = self
let d_email = fetchUsers.first!.email
caricaLavori(datore_email: d_email!)
for i in 0...lavori.count{
caricaImmagine(id_lavoro: lavori[i].id)
}
}else{
DispatchQueue.main.async {
self.performSegue(withIdentifier: "area_utente_segue", sender: self)
}
}
}catch {}
}
If you want the other 2 functions I'll edit this post (both of them loads data from php script, both do an http request)
thank you guys

You say "both of them loads data from php script, both do an http request". That is a key piece of information.
On iOS you want to do network access asynchronously. That means that a function that submits a network requests submits that request and then returns immediately, before the request has even been sent to the remote server.
The solution is to write your methods to take a completion handler. The method invokes the completion handler once the task is complete.
Take a look at my answer in the thread below for code that includes a working example of using completion handlers:
Storing values in completionHandlers - Swift
Note that that post (And the sample app it links to) was written in Swift 2, and will need to be updated for Swift 3.

Related

How to change a value outside, when inside a Dispatch Semaphore (Edited)

i have a question, and I will tell you as clear as possible:
I need to get an object to my func, create a variable version of it, change some property values one by one, and use new version of it for saving to the cloud. My problem is, when I declare my variable, if I change property values inside my Dispatch Semaphore, the variable outside not changing somehow, there is some problem that I could not understand. Here is the code :
func savePage(model: PageModel, savingHandler: #escaping (Bool) -> Void) {
// some code .....
var page = model // (1) I created a variable from function arg
let newQueue = DispatchQueue(label: "image upload queue")
let semaphore = DispatchSemaphore(value: 0)
newQueue.async {
if let picURL1 = model.picURL1 {
self.saveImagesToFireBaseStorage(pictureURL: picURL1) { urlString in
let url = urlString // (2) urlString value true and exist
page.picURL1 = url // (3) modified the new created "page" object
print(page.picURL1!) // (4) it works, object prints modified
}
}
semaphore.signal()
}
semaphore.wait()
newQueue.async {
if let picURL2 = model.picURL2 {
self.saveImagesToFireBaseStorage(pictureURL: picURL2) { urlString in
let url = urlString
page.picURL2 = url
}
}
semaphore.signal()
}
semaphore.wait()
print(page.picURL1!) //(5) "page" object has the old value?
newQueue.async {
print(page.picURL1!) //(6) "page" object has the old value?
do {
try pageDocumentRef.setData(from: page)
savingHandler(true)
} catch let error {
print("Error writing city to Firestore: \(error)")
}
semaphore.signal()
}
semaphore.wait()
}
I should upload some pictures to the cloud and get their urls, so I can create updated version of the object and save onto the old version on the cloud. But "page" object doesn't change somehow. When inside the semaphore, it prints right value, when outside, or inside another async semaphore block, it prints old value. I am new to the concurrency and could not find a way.
What I tried before :
Using Operation Queue and adding blocks as dependencies.
Creating queue as DispatchQueue.global()
What is the thing I am missing here?
Edit : I added semaphore.wait() after second async call. It actually was in my code but I accidentally deleted it while pasting to the question, thanks to Chip Jarred for pointing it.
UPDATE
This is how I changed the code with async - await:
func savePage(model: PageModel, savingHandler: #escaping () -> Void) {
// Some code
Task {
do {
let page = model
let updatedPage = try await updatePageWithNewImageURLS(page)
// some code
} catch {
// some code
}
}
// Some code
}
private func saveImagesToFireBaseStorage(pictureURL : String?) async -> String? {
//some code
return downloadURL.absoluteString
}
private func updatePageWithNewImageURLS(_ page : PageModel) async throws -> PageModel {
let picUrl1 = await saveImagesToFireBaseStorage(pictureURL: page.picURL1)
let picUrl2 = await saveImagesToFireBaseStorage(pictureURL: page.picURL2)
let picUrl3 = await saveImagesToFireBaseStorage(pictureURL: page.picURL3)
let newPage = page
return try await addNewUrlstoPage(newPage, url1: picUrl1, url2: picUrl2, url3: picUrl3)
}
private func addNewUrlstoPage(_ page : PageModel, url1: String?, url2 : String?, url3 :String?) async throws -> PageModel {
var newPage = page
if let url1 = url1 { newPage.picURL1 = url1 }
if let url2 = url2 { newPage.picURL2 = url2 }
if let url3 = url3 { newPage.picURL3 = url3 }
return newPage
}
So one async function gets a new photo url, for an old url, second async function runs multiple of this first function inside to get new urls for all three urls of the object, then calls a third async function a create and return an updated object with the new values.
This is my first time using async - await.
Let's look at your first async call:
newQueue.async {
if let picURL1 = model.picURL1 {
self.saveImagesToFireBaseStorage(pictureURL: picURL1) { urlString in
let url = urlString // (2) urlString value true and exist
page.picURL1 = url // (3) modified the new created "page" object
print(page.picURL1!) // (4) it works, object prints modified
}
}
semaphore.signal()
}
I would guess that the inner closure, that is the one passed to saveImagesToFireBaseStorage, is also called asynchronously. If I'm right about that, then saveImagesToFireBaseStorage returns almost immediately, executes the signal, but the inner closure has not run yet, so the new value isn't yet set. Then after some latency, the inner closure is finally called, but that's after your "outer" code that depends on page.picURL1 has already been run, so page.picURL1 ends up being set afterwards.
So you need to call signal in the inner closure, but you still have to handle the case where the inner closure isn't called. I'm thinking something like this:
newQueue.async {
if let picURL1 = model.picURL1 {
self.saveImagesToFireBaseStorage(pictureURL: picURL1) { urlString in
let url = urlString
page.picURL1 = url
print(page.picURL1!)
semaphore.signal() // <--- ADDED THIS
}
/*
If saveImagesToFireBaseStorage might not call the closure,
such as on error, you need to detect that and call signal here
in the case as well, or perhaps in some closure that's called in
the failure case. That depends on your design.
*/
}
else { semaphore.signal() } // <--- MOVED INTO `else` block
}
Your second async would need to be modified similarly.
I notice that you're not calling wait after the second async, the one that sets page.picURL2. So you have 2 calls to wait, but 3 calls to signal. That wouldn't affect whether page.picURL1 is set properly in the first async, but it does mean that semaphore will have unbalanced waits and signals at the end of your code example, and the blocking behavior of wait after the third async may not be as you expect it to be.
If it's an option for your project, refactoring to use async and await keywords would resolve the problem in a way that's easier to maintain, because it would remove the need for the semaphore entirely.
Also, if my premise that saveImagesToFireBaseStorage is called asynchronously is correct, you don't really need the async calls at all, unless there is more code in their closures that isn't shown.
Update
In comments, it was revealed the using the solution above caused the app to "freeze". This suggests that saveImagesToFireBaseStorage calls its completion handler on the same queue that savePage(model:savingHandler) is called on, and it's almost certainly DispatchQueue.main. The problem is that DispatchQueue.main is a serial queue (as is newQueue), which means it won't execute any tasks until the next iteration of its run loop, but it never gets to do that, because it calls semaphore.wait(), which blocks waiting for the completion handler for saveImagesToFireBaseStorage to call semaphore.signal. By waiting it prevents the very thing its waiting for from ever executing.
You say in comments that using async/await solved the problem. That's probably the cleanest way, for lots of reasons, not the least of which is that you get compile time checks for a lot of potential problems.
In the mean time, I came up with this solution using DispatchSemaphore. I'll put it here, in case it helps someone.
First I moved the creation of newQueue outside of savePage. Creating a dispatch queue is kind of heavy-weight operation, so you should create whatever queues you need once, and then reuse them. I assume that it's a global variable or instance property of whatever object owns savePage.
The second thing is that savePage doesn't block anymore, but we still want the sequential behavior, preferably without going to completion handler hell (deeply nested completion handlers).
I refactored the code that calls saveImagesToFireBaseStorage into a local function, and made it behave synchronously by using a DispatchSemaphore to block until it's completion handler is called, but only in that local function. I do create the DispatchSemaphore outside of that function so that I can reuse the same instance for both invocations, but I treat it as though it were a local variable in the nested function.
I also have to use a time-out for the wait, because I don't know if I can assume that the completion handler for saveImagesToFireBaseStorage will always be called. Are there failure conditions in which it wouldn't be? The time-out value is almost certainly wrong, and should be considered a place-holder for the real value. You'd need to determine the maximum latency you want to allow based on your knowledge of your app and its working environment (servers, networks, etc...).
The local function uses a key path to allow setting differently named properties of PageModel (picURL1 vs picURL2), while still consolidating the duplicated code.
Here's the refactored savePage code:
func savePage(model: PageModel, savingHandler: #escaping (Bool) -> Void)
{
// some code .....
var page = model
let saveImageDone = DispatchSemaphore(value: 0)
let waitTimeOut = DispatchTimeInterval.microseconds(500)
func saveModelImageToFireBaseStorage(
from urlPath: WritableKeyPath<PageModel, String?>)
{
if let picURL = model[keyPath: urlPath]
{
saveImagesToFireBaseStorage(pictureURL: picURL)
{
page[keyPath: urlPath] = $0
print("page.\(urlPath) = \(page[keyPath: urlPath]!)")
saveImageDone.signal()
}
if .timedOut == saveImageDone.wait(timeout: .now() + waitTimeOut) {
print("saveImagesToFireBaseStorage timed out!")
}
}
}
newQueue.async
{
saveModelImageToFireBaseStorage(from: \.picURL1)
saveModelImageToFireBaseStorage(from: \.picURL2)
print(page.picURL1!)
do {
try self.pageDocumentRef.setData(from: page)
// Assume handler might do UI stuff, so it needs to execute
// on main
DispatchQueue.main.async { savingHandler(true) }
} catch let error {
print("Error writing city to Firestore: \(error)")
// Should savingHandler(false) be called here?
}
}
}
It's important to note that savePage does not block the thread that's called on, which I believe to be DispatchQueue.main. I assume that any code that is sequentially called after a call to savePage, if any, does not depend on the results of calling savePage. Any that does depend on it should be in its savingHandler.
And speaking of savingHandler, I have to assume that it might update the UI, and since the point where it would be called is in a closure for newQueue.async it has to be explicitly called on DispatchQueue.main, so I do that.

Call a file-download function from multiple View Controllers; how to return results TO those VC's?

My app will need to download files from my website from several different places in the app, so it seems to make sense to write the function to accomplish the download once, put it in its own class, and call that function from each ViewController. So far, so good, things work. The download is happening, and the downloaded file will print correctly.
The problem comes when the download function goes to send a "success" or "failed" message back to the ViewController that called it, so that the VC can then react accordingly -- update the display, close out the download dialog, whatever. How to make that happen is where I'm stuck.
What I have:
Each of ViewControllerTwo and ViewControllerThree (which are identical for now, other than requesting different files from my server) calls the download function thus:
Downloader.load(url: urlForFileA!, to: localDestinationFileA, callingViewControllerNumber: 2)
The code for the downloader function (which is currently synchronous, but will eventually become asynchronous) looks like this (in its own Downloader class):
class func load(url: URL, to localUrl: URL, callingViewControllerNumber: Int) {
let sessionConfig = URLSessionConfiguration.default
let session = URLSession(configuration: sessionConfig)
let request = URLRequest(url: url, cachePolicy: .reloadIgnoringLocalAndRemoteCacheData)
let task = session.downloadTask(with: request) { (tempLocalUrl, response, error) in
if let tempLocalUrl = tempLocalUrl, error == nil {
// Got a file, might be a 404 page...
if let statusCode = (response as? HTTPURLResponse)?.statusCode {
print("Success downloading: \(statusCode)")
if statusCode == 404 {
// ERROR -- FILE NOT FOUND ON SERVER
returnToCaller(sourceIdent: callingViewControllerNumber, successStatus: .fileNotFound, errorMessage: "File not Found, 404 error")
}
}
do {
try FileManager.default.copyItem(at: tempLocalUrl, to: localUrl)
// SUCCESS!
returnToCaller(sourceIdent: callingViewControllerNumber, successStatus: .success, errorMessage: "")
} catch (let writeError) {
returnToCaller(sourceIdent: callingViewControllerNumber, successStatus: .movingError, errorMessage: "\(writeError)")
}
} else {
returnToCaller(sourceIdent: callingViewControllerNumber, successStatus: .downloadFailed, errorMessage: "Grave Unexplained Failure")
}
}
task.resume()
}
This part works.
The returnToCaller function is an admittedly ugly (okay, very, very ugly) way to send something back to the calling ViewController:
class func returnToCaller(sourceIdent : Int, successStatus : downloadSuccessStatusEnum, errorMessage : String) {
switch sourceIdent {
case 2:
ViewControllerTwo().returnFromDownload(successStatus: successStatus, errorMessage: errorMessage)
case 3:
ViewControllerThree().returnFromDownload(successStatus: successStatus, errorMessage: errorMessage)
default:
fatalError("Unknown sourceIdent of \(sourceIdent) passed to func returnToCaller")
}
}
The problem is that when that returnFromDownload function in the original ViewController is called, it isn't aware of anything in the VC that's loaded -- I go to change the background color of a label, and get a runtime error that the label is nil. The label exists, but this call into the ViewController code is happening in isolation from the running, instantiated VC itself. (Probably the wrong vocabulary there -- apologies.) The code runs and can print but errors out when interacting with anything in the View itself.
The more I work with this, the less confident I am that I'm on the right track here, and my limited experience with Swift isn't enough to see what needs to be happening so that the download function can do all its work "over here" and then return a success/failure message to the calling VC so that the VC can then work with it.
This question seems to be asking something similar; the one answer there doesn't address my (nor, I think, his) root question of how to get code within the presented VC running again with the results of what happened outside the VC (manager approval in his case, download in mine).
Not asking for my code to be rewritten (unless it's a quick fix), but needing to be pointed in the right direction. Many thanks!
What you want can be accomplished pretty easily with a closure.
The first step is to add another parameter to your load method and remove your callingViewController param:
class func load(url: URL, to localUrl: URL, completion: (downloadSuccessStatusEnum, String) -> Void)
This will allow you to call completion instead of returnToCaller when your method completes like so:
DispatchQueue.main.async {
completion(.success, "Insert your error message here")
}
Lastly, to call this method you simply need to call the method like so in your VCs:
Downloader.load(url: nameOfYourURL, to: destinationName) { statusEnum, errorString in
// Insert your code you want after the request completes here
}

Waiting for Asynchronous function call to complete

I know this question has been asked before, but all solutions do not work for me.
I have a function with sends parameters to an API, and returns the data as a list, I have a UITableView set up to use that list, but it runs before the list is assigned to a variable.
code:
var functionResult = [String]()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
//gradesscrollView.contentSize.height = 3000
fetchItems{ (str) in
var returnedItems = [String]()
let result = self.convertoArray(itemstoPass: str!)
for i in result{
functionResult.append(i)
}
}
self.tableofItems.delegate = self
self.tableofItems.dataSource = self //Data source is set up to use functionResult, however functionResult is empty before fetchItem runs.
}
I would appreciate it if it is not immediately voted as a duplicate, here is what I have tried.
Dispatch groups
Semaphore timing
running variables
including self.tableofItems.delegate = self & self.tableofItems.dataSource = self in the fetchItems{ (str) in part.
EDIT:
Fetch items has been requested,
func fetchItems(completionHandler: #escaping (String?) -> ()) -> () {
let headers = [
"Content-Type": "application/x-www-form-urlencoded"
]
//Switch to keychain
let username = UserDefaults.standard.object(forKey: "username") as! String?
let password = UserDefaults.standard.object(forKey: "password") as! String?
let usernametoSend = username!
let passwordtoSend = password!
print(usernametoSend)
print(passwordtoSend)
let parameters: Parameters = [
"username": usernametoSend,
"password": passwordtoSend
]
Alamofire.request("https://www.mywebsite.com/API/getItems", method: .post, parameters: parameters, headers: headers)
.responseString { response in
completionHandler(String(response.result.value!))
You can't - and shouldn't - wait until an async call to complete. You need to study async programming until you understand it.
An async function accepts a job to do, and returns immediately, before the job is done.
in Swift you usually write an async function to take a completion handler, which is a block of code that you want to be run one the async task is complete.
I have a project called Async_demo (link) on Github that illustrates this. It implements a DownloadManager class that handles async downloads.
The key part is the function downloadFileAtURL(), which should more properly be named downloadDataAtURL, since it returns in-memory data rather than a file.
I created that function to take a completion handler as a parameter:
/**
This function demonstrates handling an async task.
- Parameter url The url to download
- Parameter completion: A completion handler to execute once the download is finished
*/
func downloadFileAtURL(_ url: URL, completion: #escaping DataClosure) {
//We create a URLRequest that does not allow caching so you can see the download take place
let request = URLRequest(url: url,
cachePolicy: .reloadIgnoringLocalAndRemoteCacheData,
timeoutInterval: 30.0)
let dataTask = URLSession.shared.dataTask(with: request) {
//------------------------------------------
//This is the completion handler, which runs LATER,
//after downloadFileAtURL has returned.
data, response, error in
//Perform the completion handler on the main thread
DispatchQueue.main.async() {
//Call the copmletion handler that was passed to us
completion(data, error)
}
//------------------------------------------
}
dataTask.resume()
//When we get here the data task will NOT have completed yet!
}
}
It uses an NSURLSession to download a block of data from the specified URL. The data request call I use takes a completion handler that gets executed on a background thread. In the completion handler that I pass to the data task, I invoke the completion handler that's passed in to the downloadFileAtURL() function, but on the main thread.
The code you posted is kind of confusing. It isn't clear which part is the async function, what the flow is, or what data is needed to display your table view.
If you rewrite your function that does async work to take a completion block then you could call tableView.reloadData() in your completion block. (Make sure that call is performed on the main thread.)
EDIT:
As others have said, you need to edit your question to show the code for your fetchItems() function.
I'm guessing that that function is the one that does the Async work, and that the block after it is a completion handler that gets performed asynchronously. If so, you should probably refactor your code like this:
var functionResult = [String]()
override func viewDidLoad() {
super.viewDidLoad()
//I moved these lines above the call to fetchItems to make it clear
//that they run before fetchItems' completion closure is executed
self.tableofItems.delegate = self
self.tableofItems.dataSource = self //Data source is set up to use functionResult, however functionResult is empty before fetchItem runs.
print("Step 1")
fetchItems{ (str) in
var returnedItems = [String]()
let result = self.convertoArray(itemstoPass: str!)
for i in result{
functionResult.append(i)
}
print("Step 3")
DispatchQueue.main.async() {
tableview.reloadData() //Do this from the main thread, inside the closure of `fetchItems()`
}
}
print("Step 2")
}
You should load the data of the list in the method of loadView, so that it will be loaded early before UITableView reads.
Sometimes, viewDidLoad performs a little bit slowly. Generally, people will initialize the data of list or sth in the method of loadView to make sure the data is completed before view is created.

Cannot signal semaphore with Firebase observeEventType - what gives?

I am using Firebase to read/write data to a remote server.
My objective is to write a routine that also takes a callback function. Heres what the routine should accomplish:
Write some data to Firebase (this works fine)
Observe for changes on above written data
If change occurs call callback with success
If a timeout is triggered, call callback with failure
Im unable to figure out why steps 2-4 are failing for me. Below is a snippet of the code
Here's whats going on in the code:
It sets up a GCD semaphore
It writes some data to the root firebase URL - specifically it adds a user called joe. This works fine. I can see the data written from Vulcan
it sets up a reference to Joe's node and watches for events on childAdded for Joe. Here is the API reference
Upon successfully getting an event it signals the semaphore, which should call the callback with message "Success"
Instead I see the "timeout" message. Strangely though the observer does print out the newly added key:value pair, which is doubly confusing!
Whats going on here? Am I using semaphores incorrectly? Or am i using Firebase's API incorrectly?
typealias completionfoo = (gid:String) -> Void
func setStateReady(somestr: String, callfoo: completionfoo) {
let semaphore = dispatch_semaphore_create(0)
var myRootRef = Firebase(url:"https://xxxxxx.firebaseio.com/")
var joe = ["state" : "READY", "msg" : somestr]
var usersRef = myRootRef.childByAppendingPath("users")
var users = ["joe": joe]
usersRef.setValue(users)
var joeref = Firebase(url: "https://xxxxxx.firebaseio.com/users/joe/")
// Read data and react to changes
joeref.observeEventType(.ChildAdded, withBlock: {
snapshot in
print(snapshot.key)
print(snapshot.value)
dispatch_semaphore_signal(semaphore)
})
let timeout = dispatch_time(DISPATCH_TIME_NOW, Int64(30 * Double(NSEC_PER_SEC)))
if dispatch_semaphore_wait(semaphore, timeout) != 0 {
joeref.removeAllObservers()
callfoo(gid: "timeout")
} else {
joeref.removeAllObservers()
callfoo(gid: "success")
}
}
override func viewDidLoad() {
super.viewDidLoad()
setStateReady("hi i am joe") { (gid) -> Void in
print(gid)
}

xcode present segue on restful callback (swift)

I am self taught Swift user and trying to do something simple but it's got me pretty stumped. I have a simple registration form. After submitting the items for registration, I want to move the page to a "how it works" page via a segue, but ONLY when my restful API returns success. Here's what I have so far; feel free to send me a better way to do this as well. All criticisms are welcome.
let myUrl = NSURL(string:"http://www.example.com/scripts/Register.php")
let request = NSMutableURLRequest(URL: myUrl!)
request.HTTPMethod = "POST"
let postString = "email=\(email)&password=\(pass)"
request.HTTPBody = postString.dataUsingEncoding(NSUTF8StringEncoding)
let task = NSURLSession.sharedSession().dataTaskWithRequest(request){
data, response, error in
if (error != nil) {
println("Error: \(error)")
return
}
var err: NSError?
var json = NSJSONSerialization.JSONObjectWithData(data, options: .MutableContainers, error: &err) as? NSDictionary
var showTutorial : Bool = false
if let parseJSON = json {
var returnValue = parseJSON["status"] as? String
println("Status: \(returnValue)")
var isUserRegistered: Bool = false
if (returnValue == "Success") {
showTutorial = true
} else if (returnValue == "Error") {
// handle error
}
}
// if successful registration, show how it works page
if (showTutorial) {
self.performSegueWithIdentifier("howItWorksSegue", sender: self)
}
}
task.resume()
I have a segue named howItWorksSegue attached to this view controller going to the HowItWorksViewController. I'm receiving this error from Xcode:
2015-10-12 21:22:43.261 ZiftDine[11396:2307755] Assertion failure in -[UIKeyboardTaskQueue waitUntilAllTasksAreFinished], /SourceCache/UIKit_Sim/UIKit-3347.44.2/Keyboard/UIKeyboardTaskQueue.m:374
2015-10-12 21:22:43.391 ZiftDine[11396:2307755] Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: '-[UIKeyboardTaskQueue waitUntilAllTasksAreFinished] may only be called from the main thread.'
Anything done with UI should be done on the main thread, try wrapping you performSegue call like this:
dispatch_async(dispatch_get_main_queue(),{
self.performSegueWithIdentifier("howItWorksSegue", sender: self)
})
#Swinny89 gave the solution to your problem but some explanation is in order.
If you read the description of dataTaskWithRequest:completionHandler:, which is the method you are using (although your Swift code uses trailing closure syntax to drop the completionHandler label and put the closure outside the parentheses) it says:
completionHandler: The completion handler to call when the load
request is complete. This handler is executed on the delegate queue.
Then if you read the description of the init method sessionWithConfiguration:delegate:delegateQueue: it says:
queue: A queue for scheduling the delegate calls and completion
handlers. If nil, the session creates a serial operation queue for
performing all delegate method calls and completion handler calls.
Serial operation queues run on a different thread.
So, taking all of those pieces of information together, it means that your completion closure is going to be executed on a thread other than the main thread.
A cardinal rule of iOS/Mac development is that you must do all UI calls from the main thread. If a call changes anything on the screen, it's a UI call.
Your code is invoking performSegueWithIdentifier: from a background thread. It changes what's displayed on the screen, so it must be a UI call. Therefore it needs to be run on the main thread.
The GCD function dispatch_async(), with a queue of dispatch_get_main_queue(), submits a closure to be run on the main dispatch queue, a queue that runs on the main thread.
So Swinny's solution fixes your problem.
The take-away here:
Any time you are running code in a closure, stop and think: "Am I positive that this closure will always be run on the main thread?" If the answer is no, enclose the code in a call to dispatch_async(dispatch_get_main_queue(), like Swinny's answer.
The answers by #Duncan C and #Swinny89 are good. For anyone coming in from Google, the syntax in Swift 3 has changed a little:
DispatchQueue.main.async(execute: {
self.performSegueWithIdentifier("howItWorksSegue", sender: self)
})

Resources