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([])
}
}
}
_ completionHandler
argument in fetchOrders
mean?(orders: () throws -> [Order])
mean? PS : I am new to iOS
and Swift
The SWIFT code is a Business Identification Code (BIC) assigned to banks by SWIFT as an easy cross-border payment solution. For any transaction this bank makes on an international level, the SWIFT code is used. The purpose of the code is to act as an international digital language to conveniently conduct payments overseas.
SWIFT is key to the way most traditional banks process international transfers, as they know they can rely on the standards and security used within the SWIFT payment and messaging network.
Is a SWIFT/ BIC code the same as a sort code? Nope, sort codes aren’t the same as SWIFT codes. Sort codes are 6-digit codes that help British and Irish banks to identify bank branches for domestic payments (payments within a country). Do all banks use BIC/ SWIFT codes?
The financial cousin to SWIFT is IBAN – the International Bank Account Number. This is another code often needed to send money overseas. While the SWIFT code stands as a kind of international bank ID, the IBAN represents the accounts within a bank.
There's quite a lot in here, so we'll break it down one piece at a time:
func fetchOrders(_ completionHandler: (_ orders: [Order]) -> Void)
fetchOrders
.completionHandler
) and returns nothing._
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.)completionHandler
is the "internal name," what the parameter is called inside the function.completionHandler
is (_ orders: [Order]) -> Void
. We'll break that down now.
[Order]
(array of Order
) and returns Void
. Informally this means "returns nothing" but literally means it returns the empty tuple ()
._ 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.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
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.{ orders in
, but then the reader would probably have been surprised by this somewhat unusual code.
orders
that takes nothing and returns [Order]
or throws an error. Basically this is a way to say that fetchOrders
might fail.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([])
}
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.
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.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:
Order
as a parameter and acts as a callback.If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With