Swift 3.0: Paramater to check for action completion - ios

I recently started learning app development and almost every tutorial I can find is not in swift 3, so sometimes I run into confusion when it comes to the syntax for certain things that have been changed.
//Take the user to the game screen from the intro scene
let introLabel = childNode(withName: "introLabel")
if introLabel != nil{
let fadeOut = SKAction.fadeOut(withDuration: 1)
introLabel?.run(action: fadeOut, completion: () -> Void)
}
I have searched all around the internet and can't seem to find the missing thing I am supposed to put here (By completion: )

completion: () -> Void
It say that it will call a function have no parameter () and return type is Void
The function is like this
func handleCompletion() -> Void {
//Do something when complete
}
In your code, you can use like this.
introLabel?.run(action: fadeOut, completion: handleCompletion)
handleCompletion is my function above
Your can google for this by use closure swift or first class function swift keyword

Related

How do I avoid callback hell on swift functions that I didn't write?

I don't want this to be misconstrued as a duplicate. I want to deal with callback hell arising from API calls from Firestore (database by Firebase, a Google platform). I can't modify their function declarations, so I assume I will have to wrap their functions with some of my code.
For example, in the code below, the function eventCreatedSuccessfully() can only be called after the asynchronous function completes. eventCreatedSuccessfully() also contains a function call to firebase that has a closure, which another function relies on and etc...Though this isn't causing me problems right now, it probably will as my App grows larger and larger. I researched online and found solutions like Futures and Streams from third-party frameworks, but I didn't know how to integrate them into code I have no control over (the API calls).
batch.commit { (error) in
self.dismiss(animated: true) {
if error == nil {
self.eventCreatedSuccessfully()
print("Event created successfully")
} else {
print(error!.localizedDescription)
}
}
}
Wrap the calls in promises. Any of the popular libraries will do the trick. The one that comes to mind is PromiseKit, available (at the time of this writing) at https://github.com/mxcl/PromiseKit.
Here is code I wrote for a work project (it's open source) which wraps a function that takes a completion, and returns a Promise which will signal with the result when the completion is called. It's using an internal Promise implementation, but the process can be adapted to other implementations.
public func promise<Return>(_ task: (#escaping (Return?, Error?) -> ()) -> ()) -> Promise<Return> {
let p = Promise<Return>()
task { (value: Return?, error: Error?) -> Void in
if let error = error {
p.signal(error)
}
if let value = value {
p.signal(value)
}
}
return p
}
The completion is expected to be called with a result of some kind, or an error. Adapt as required for your use-case.
An example usage follows.
public typealias BalanceCompletion = (Balance?, Error?) -> Void
func balance(completion: #escaping BalanceCompletion) {
guard deleted == false else {
completion(nil, KinError.accountDeleted)
return
}
Stellar.balance(account: stellarAccount.publicKey!, asset: asset, node: node)
.then { balance -> Void in
completion(balance, nil)
}
.error { error in
completion(nil, KinError.balanceQueryFailed(error))
}
}
func balance() -> Promise<Balance> {
return promise(balance)
}
I researched online and found solutions like Futures and Streams (...)
In most cases futures and streams is all about PromiseKit and RxSwift frameworks.
If you have only big amount of closures try to use PMK. It's very simple and easy to use. PMK also has nice documentation section on github.
RxSwift is more advanced level, because it requires you to write code fully to paradigm of itself - starts from server/firebase request and ends with ui. Also, there is a good note at PMK github about difference of these two.
Also, should be note, that google also has nice library called promises. According to their benchmarks google's library is leader in almost all nominations.

Place/City names from a list of CLLocation

Here is my situation. (Using Swift 2.2)
I have a list of coordinates (CLLocation). I need to call the reverseGeocodeLocation to fetch the corresponding Place/City. If I try to loop through the elements there is a chance for some calls to fails as Apple suggest to send one call in a second. So I need to add a delay between each calls as well.
Is there any way to achieve this? Any help is appreciated.
(If we have multiple items with same lat, long we only call the api once)
This code declares a set of locations and looks them up one by one, with at least 1 second between requests:
var locations = Set<CLLocation>()
func reverseGeocodeLocation() {
guard let location = locations.popFirst() else {
geocodingDone()
return
}
CLGeocoder().reverseGeocodeLocation(location) { placemarks, error in
//Do stuff here
//Dispatch the next request in 1 second
_ = Timer.scheduledTimer(withTimeInterval: 1, repeats: false) { _ in
self.reverseGeocodeLocation()
}
}
}
func geocodingDone() {
//Put your finish logic in here
}
FYI I used the block syntax for the Timer, but that only works on iOS 10. If you are using iOS 9 or earlier just use the selector version and it works the same way.

Swift - How to call a function after a function is complete?

i am new in swift.
I have been trying to google around.
My question is, how can i call a function after a function is complete?
So far i am using a delay, but sometimes the delay is not in sync.
The problem i try to solve is to download a URL from firebase database, and then proceed to download a image from Firebase.
You have to use a closure.
func funcA() {
funcB(){
//Manage completion handler
}
}
func funcB(completion: () -> Void) {
completion()
}

To wait in a loop (that backgrounds anyway) in Swift?

In Swift (that's Swift) there are a number of ways to handle asynchronous,
Say you have a loop like this - it's calling a parse cloud code call which goes to background anyway.
public func runImages()
{
print("test begins...")
for i in 1...3
{
print("Tick tock tick tock ..\(i)")
PFCloud.callFunctionInBackground("blah", withParameters:["bla":i,"bla":"bla] )
{
(response: AnyObject?, error: NSError?) -> Void in
print(".. done! Now go again...")
if let rr = response as? String { print(rr) }
if let err = error { print(err.domain) }
}
}
}
How to make that wait for the end of each PFCloud call?
Really is just an ordinary flag best, or? (Note that (a) I can't get a flag to work in Swift and (b) as Paul points out you're blocking the UI!!)
What is the "Swift way" in the context you see here? I feel it would be very inelegant to use a recursive pattern here, for example.
If you want the three calls to execute serially then you can use a serial dispatch queue and a dispatch_barrier_async to do something when all three are finished -
let dispatchQueue=dispatch_queue_create("queue", DISPATCH_QUEUE_SERIAL)
for i in 1...3 {
dispatch_async(dispatchQueue, { () -> Void in
print("i=\(i)")
let result = PFCloud.callFunction("blah", withParameters:["bla":i,"bla":"bla] )
})
}
dispatch_barrier_async(dispatchQueue, { () -> Void in
print("really done")
})
print(" done")
In order for this to work with your Parse function you need to use the synchronous cloud code call, not an asynchronous. And if you update UI in the dispatch_barrier_async closure you would need to dispatch that on the main queue.

iOS takes long time to update view after HTTP request?

I am very new to learning iOS and Swift, so there may be something very basic here that I don't understand. I am using the agent library to send HTTP requests in Swift. Right now I'm just getting the hang of creating the request and parsing the JSON response.
I have a very simple UI with a button and a UILabel that I want to update with the results of some JSON.
Here is my code:
func updateWithJson() -> Void {
let req = Agent.get("http://xkcd.com/info.0.json")
req.end({ (response: NSHTTPURLResponse!, data: Agent.Data!, error: NSError!) -> Void in
let json = data! as Dictionary<NSString, NSString>
// this takes almost 30 seconds to propagate to the UI...
self.updateMe.text = json["safe_title"]!
})
}
The part I don't understand is the self.updateMe.text = json["safe_title"]! statement which is just updating some text on a UILabel called updateMe. It takes almost a full 30 seconds for this to reflect in the UI.
I know that the HTTP request itself is very fast - if I curl that URL it comes back instantaneously. It also seems like the Agent object is making the connection and returning the response pretty fast.
Am I missing something very basic? Should I be updating the UI in a different way? All pointers are appreciated!
UPDATE
Through another SO post it's my understanding that the block inside of req.end is a background thread and I need to do UI updates on the main thread. I updated my function to look like this and I get the desired result. However, now I'm wondering if there's something incorrect about doing it this way?
func updateWithJson() -> Void {
let req = Agent.get("http://xkcd.com/info.0.json")
req.end({ (response: NSHTTPURLResponse!, data: Agent.Data!, error: NSError!) -> Void in
let json = data! as Dictionary<NSString, NSString>
var text = json["safe_title"]!
dispatch_sync(dispatch_get_main_queue()) {
self.updateMe.text = text
}
})
}
What's happening is that your HTTP request is running on a background thread. When it calls the callback you provide, you're still on that background thread. In iOS all UI work must be done on the main thread. The easiest way to do this is by using GCD's dispatch_async like so:
dispatch_async(dispatch_get_main_queue()) {
[weak self] in
self?.updateMe.text = json["safe_title"]!
return
}
So your entire function would look like:
func updateWithJson() -> Void {
let req = Agent.get("http://xkcd.com/info.0.json")
req.end({ (response: NSHTTPURLResponse!, data: Agent.Data!, error: NSError!) -> Void in
let json = data! as Dictionary<NSString, NSString>
dispatch_async(dispatch_get_main_queue()) {
[weak self] in
self?.updateMe.text = json["safe_title"]!
return
}
})
}
The bit about [weak self] in is so you don't create a strong reference cycle. The return at the end is there because you have a closure with only one expression in it. In that case, Swift will try to implicitly return a value based on that statement and in this case that's not what you want.

Resources