I have been following a video tutorial, and have written the following code:
func downloadWeatherDetails(completed: ()->() ) {
let currentWeatherURL = URL(string: CURRENT_WEATHER_URL)!
Alamofire
.request(currentWeatherURL)
.responseJSON(completionHandler: { response in
let result = response.result
print(result)
})
completed()
}
So basically, my understanding is as follows. The .responseJSON handler lets you call code after the request has been fired. It allows you to specify a completionHandler, which in my case, is the closure:
{ response in
let result = response.result
print(result)
}
However, what I don't understand is what the "response" keyword actually signifies. I researched the usage of closures and saw that the syntax is:
{(param) -> returnType in { code here }
Thus, is the "response" keyword a parameter? If so, how is it being declared and where is the data coming from? How is the data passed into the "response" object? Also, why is only one parameter allowed? The code did not work if I made it as follows, for example:
{ (response, test) in
let result = response.result
print(result)
}
I would really appreciate a thorough explanation on this as I've found no help elsewhere online. I've gone through Apple's "The Swift Programming Language", a multitude of different explanations, and similar questions, but still do not understand completely.
Just to clarify, I do not believe my question is a duplicate since my question revolves primarily on the captured value stored in response rather than the syntax of closures as a whole. I went through the linked question while trying to figure out my own problem, but it did not help me sufficiently.
Minor clarification needed:
Is it always the case that when a method takes a closure as one of its parameters, for example, .testMethod(testParam: (String) -> ()) and would thus in practice be used: .testMethod(testParam: { (capturedVar) in statements} (correct me if im wrong), is it always the case that the parameter of the closure ((String) in this case) will be captured and stored in capturedVar? Will there always be data passed into the variable you define? Or is this cycle specific to alamofire?
Swift closures are defined as:
{ (parameters) -> return_type in
statements
}
That is, the names in parenthesis are the variables the closure has captured, and the -> type is the optional return type (optional because the compiler can usually infer it). Alamofire's responseJSON method captures a DataResponse<Any> parameter, which you can name whatever you want, but which is usually just named response. You can then access it inside that closure.
Also, your completed() call should be inside the responseJSON call, not outside, otherwise it just gets called immediately.
Related
I have a call to a URLSession:
var someVar = "Are you in my scope?"
let task = session.dataTask(with: url, completionHandler: updatePlaces)
Where updatePlaces is a function defined as:
private func updatePlaces(data: Data?, response: URLResponse?, error: Error?) -> Void
I split it up into another function because I really don't like having this as one large block of code with my "updatePlaces" function as a closure in my original session.dataTask. It just seems to be doing too much in one function. I want to split it up.
I can also make a closure using the syntax below, but I see no difference between this and the function (I understand a function is a special type of closure, and I see no difference):
lazy var updatePlaces: (Data?, URLResponse?, Error?) -> Void = {(data, response, error) in
However, earlier you saw I added someVar to the scope. With the function and the lazy var, I do not have access to someVar. However, if I make the closure inside the session.dataTask, someVar is captured and I can reference it per the docs:
Closures can capture and store references to any constants and
variables from the context in which they are defined. This is known as
closing over those constants and variables. Swift handles all of the
memory management of capturing for you.
So... I have two specific questions.
Are there ANY differences between my function declaration and my closure declaration and just passing that to completion handler.
Is there any way to capture the references in the original function if I don't define the closure in it? I'm guessing not.
And a more... generic question: What is the preferred way of handling this?
I have the following function in Swift 3
func fetchOrders(_ completionHandler: (_ orders: [Order]) -> Void)
{
ordersStore.fetchOrders { (orders: () throws -> [Order]) -> Void in
do {
let orders = try orders()
completionHandler(orders)
} catch {
completionHandler([])
}
}
}
What does _ completionHandler argument in fetchOrders mean?
What does (orders: () throws -> [Order]) mean?
PS : I am new to iOS and Swift
There's quite a lot in here, so we'll break it down one piece at a time:
func fetchOrders(_ completionHandler: (_ orders: [Order]) -> Void)
This is a function called fetchOrders.
It has one parameter (completionHandler) and returns nothing.
The first _ indicates that there is no "external name" of the first parameter. That is, you do not have to label it (in fact, you cannot). (For subtle reasons that don't really matter here, I believe the author made a mistake using _ there, and I would not have done that.)
The completionHandler is the "internal name," what the parameter is called inside the function.
The type of completionHandler is (_ orders: [Order]) -> Void. We'll break that down now.
This value is a closure that takes an [Order] (array of Order) and returns Void. Informally this means "returns nothing" but literally means it returns the empty tuple ().
The _ orders: syntax is in practice a comment. In principle the _ is an external name (but that's the only legal external name for a closure), and orders is an internal name, but in reality, closures parameters do not have names in any meaningful way, so this is purely informational.
I believe this is a poor use of the closure parameter commenting system. Since orders tells us nothing more than [Order], I would have omitted it, and made the type just ([Order]) -> Void.
Now we'll turn to the next line:
ordersStore.fetchOrders { (orders: () throws -> [Order]) -> Void in
This calls the fetchOrders method on ordersStore. We can tell from this code that fetchOrders takes a closure parameter. This is called "trailing closure" syntax in Swift, and is why I would not have used the _ for our closure. With trailing closure syntax, the external name of the parameter is not needed.
The author has provided type information here that probably wasn't necessary, but we can explore it anyway. This could likely have been written as just { orders in, but then the reader would probably have been surprised by this somewhat unusual code.
We have been passed a closure called orders that takes nothing and returns [Order] or throws an error. Basically this is a way to say that fetchOrders might fail.
The author is working around an awkwardness in Swift's throws system, which does not have a natural way to express an asynchronous action that might fail. This is one way to fix it; you pass a throwing (i.e. a possibly failing) function. I don't favor this approach, I favor using a Result enum for this case because I think it scales better and avoids possible unintended side effects, but that's a debatable point (and the Swift community hasn't really decided how to deal with this common problem).
This all leads us to:
do {
let orders = try orders()
completionHandler(orders)
} catch {
completionHandler([])
}
This is where the orders closure is evaluated. (This is very important; if orders has side effects, this is when they occur, which may be on a different queue than was intended. That's one reason I don't favor this pattern.) If the closure succeeds, we return its result, otherwise we return [] in the catch below.
In this particular case, the throws approach is slightly silly, because it's silently flattened into [] without even a log message. If we don't care about the errors, then failure should have just returned [] to start with and not messed with throws. But it's possible that other callers do check the errors.
In either case, we call the completionHandler closure with our result, chaining this back to our original caller.
This do/catch block could have been more simply written as:
let completedOrders = try? orders() ?? []
completionHandler(completedOrders)
This makes it clearer that we're ignoring errors by turning it into an optional, and avoids code duplication of the call to completionHandler.
(I just add the extra let binding to make the code a little easier to read; it isn't needed.)
The completionHandler argument means that the expected parameter (named completionHandler) must be a function that takes a list of Order objects and does not return any value.
completionHandler is the a variable name. In this specific example, this variable is a callback. You know is a callback function because (orders: [Order]) -> Void is it's data type; in this particular case, said data type is a function that receives an array of Order objects in a variable _orders and doesn't have a return value (the Void part).
TL;DR:
it's the variable name, of type:
function which receives an array of Order as a parameter and acts as a callback.
I am trying to understand how parameters passed to a method are available to nested closures. I'm nervous that something I wrote won't always have the original parameters available.
(these are drastically simplified examples)
I have a method that I wrote that specifies a closure as a parameter:
func saveNameAndAgeToServer(serverParams: [String:String], completionHandler: (age: NSNumber) -> ()) {
// Connect to a server
// POST a name and dob from serverParams
// Receives a current age in completion:
completionHandler(age: 22)
}
Now somewhere else I create another method, that also specifies a closure, takes two parameters and calls the first function:
func AwesomeFunc(name: String, dob: NSDate, completionHandler: (isOverTwentyOne: Bool) -> ()) {
let formattedDob = NSDateFormatter().stringFromDate(dob)
saveNameAndAgeToServer([name:formattedDob]) { (age) -> () in
if (age as Int) >= 21 {
print("\(name) can have a beer.")
completionHandler(isOverTwentyOne: true)
} else {
print("\(name) is too young to drink, he can have a water.")
completionHandler(isOverTwentyOne: false)
}
}
}
Am I able to guarantee that the parameters (name and dob) passed into this latter function will always be available?
What I'm trying to ask is will the memory that the saveNameAndAgeToServer closure runs within always have the parameters of AwesomeFunc available to it? I'm pretty sure the function is all being held while whatever it calls is completed but would love a 2nd opinion.
You are correct, captured variables will last for the life of the closure. Here's an exert on capturing variables from apple's swift documentation:
A closure can capture constants and variables from the surrounding
context in which it is defined. The closure can then refer to and
modify the values of those constants and variables from within its
body, even if the original scope that defined the constants and
variables no longer exists.
In Swift, the simplest form of a closure that can capture values is a
nested function, written within the body of another function. A nested
function can capture any of its outer function’s arguments and can
also capture any constants and variables defined within the outer
function.
https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Closures.html
I am building an app using Swift for the first time and using the AlamoFire library. I've built apps using Obj-C and AFNetworking before, but I'm having a hard time groking this Swift response method:
Alamofire.request(.GET, "http://someapi.com/thing.json")
.responseJSON { _, _, JSON, _ in
println(JSON)
}
The actual method definition is:
public func responseJSON(options: NSJSONReadingOptions = .AllowFragments, completionHandler: (NSURLRequest, NSHTTPURLResponse?, AnyObject?, NSError?) -> Void) -> Self {
return response(serializer: Request.JSONResponseSerializer(options: options), completionHandler: { request, response, JSON, error in
completionHandler(request, response, JSON, error)
})
}
I don't really understand what's going on here when I use this response method.
Why am I not using parens in the method call?
Am I just passing a block or anonymous function into this method?
What is the significance of passing underscores (_)?
What is the in keyword doing?
It's all here:
https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Closures.html#//apple_ref/doc/uid/TP40014097-CH11-ID102
No parens: that's trailing closure syntax. Idea is that closures can get long, hard to remember/determine long-distance paren pair.
Yes, block = anonymous function = (anonymous) closure. Yes, you're passing that as the only parameter. Since it's omitted, 'options' gets its default value of '.AllowFragments'. Trailing closure { ... } gets bound to completionHandler parameter.
The '_' is the 'don't care about this parameter' syntax ... e.g. if the function doesn't use the parameter, no point to giving it a local name.
in is part of closure syntax: indicates start of function body. Definitely read the whole closure syntax chapter above. It's designed to be extremely terse, nothing intuitive about it.
C.f. Apple's website page on Swift: https://developer.apple.com/swift/
Are there blocks in Swift like in objective-c? How are they created and called?
How would do an asynchronous request in Swift?
Is it easy to create block related memory leaks in swift? If yes, how would you avoid them?
The Swift equivalent of an (Objective-)C block is called a closure. There's a whole chapter about them in The Swift Programming Language book.
Depending on the context where you use a closure, you can declare/use it with very concise syntax. For example, a method that takes a completion handler whose signature is (success: Bool, error: NSError) - > Void can be called like this:
someMethod(otherParameters: otherValues, completionHandler:{ success, error in
if !success { NSLog("I am a leaf on the wind: %#", error) }
})
There's also a trailing closure syntax that reads nicely in cases where a closure essentially provides flow control. And you can drop the parameter names when you want to be really brief (at some cost to readability, but that's okay in some obvious cases like the below). Often a return statement is implicit, too.
myArray.sort { $0 < $1 }
let squares = myArray.map { value in
value * 2
}
Swift itself doesn't have anything for asynchronous requests, so you use existing API for that. You can use the trailing closure syntax, though:
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)) {
// do some async stuff
NSOperationQueue.mainQueue().addOperationWithBlock {
// do some main thread stuff stuff
}
}
In most cases, you don't need to worry about creating reference cycles with Swift closures the way you do with ObjC blocks. To put it simply, the capture semantics are similar enough to "just work" the way you want it to for most stuff, but different enough that the common patterns for block/closure uses (e.g. dispatch to background/main thread and referencing self's properties) don't cause cycles.
Cycles are still possible, though, and there is a solution for them. This answer's a bit long already, so check out Strong Reference Cycles for Closures in the docs for the complete explanation.
Blocks in Swift are called closures. They operate much the same as blocks (though are more flexible, and operate in more places). Reference cycles are possible with closures in Swift, and can be avoided with closure capture lists.
“Swift provides an elegant solution to this problem, known as a closure capture list. However, before you learn how to break a strong reference cycle with a closure capture list, it is useful to understand how such a cycle can be caused”
Excerpt From: Apple Inc. “The Swift Programming Language.” iBooks. https://itun.es/us/jEUH0.l
As I said in another question, you have many ways offered to pass a block equivalent to function in Swift.
I found three.
To understand this I suggest you to test in playground this little piece of code.
func test(function:String -> String) -> String
{
return function("test")
}
func funcStyle(s:String) -> String
{
return "FUNC__" + s + "__FUNC"
}
let resultFunc = test(funcStyle)
let blockStyle:(String) -> String = {s in return "BLOCK__" + s + "__BLOCK"}
let resultBlock = test(blockStyle)
let resultAnon = test({(s:String) -> String in return "ANON_" + s + "__ANON" })
println(resultFunc)
println(resultBlock)
println(resultAnon)
Update: There are 2 special cases to the Anonymous function.
The first is that function signature can be inferred so you don't have to rewrite it.
let resultShortAnon = test({return "ANON_" + $0 + "__ANON" })
The second special case works only if the block is the last argument, it's called trailing closure
Here is an example (merged with inferred signature to show Swift power)
let resultTrailingClosure = test { return "TRAILCLOS_" + $0 + "__TRAILCLOS" }
Finally, as an example:
Using all this power what I'd do is mixing trailing closure and type inference (with naming for readability)
PFFacebookUtils.logInWithPermissions(permissions) {
user, error in
if (!user) {
println("Uh oh. The user cancelled the Facebook login.")
} else if (user.isNew) {
println("User signed up and logged in through Facebook!")
} else {
println("User logged in through Facebook!")
}
}