Kan snelle sluitingen worden ingesteld op een standaardwaarde bij gebruik als parameter in een functie?

Een behoorlijk handige functie van Swift-functies is dat functieparameters standaardwaarden:

func someFunction(parameterWithDefault: Int = 42) {
    //if no arguments are passed to the function call,
    //value of parameterWithDefault is 42
}

Als een parameter een afsluiting is, is er dan een manier om deze een standaardwaarde te geven? Zie onderstaand voorbeeld:

func sendBody(
    body: NSData? = nil,
    success: (data: NSData) -> Void,
    failure: (data: NSData?) -> Void) {
}

Is er een manier om de ontwikkelaar niet te dwingen een waarde voor successof failuredoor te geven bij het aanroepen van sendBody?


Antwoord 1, autoriteit 100%

Ja, functies zijn slechts waarden, dus u kunt ze als standaard opgeven

// just to show you can do it with inline closures or regular functions
func doNothing<T>(t: T) -> Void { }
func sendBody(
    body: NSData? = nil,
    success: (data: NSData) -> Void = { _ in return },
    failure: (data: NSData?) -> Void = doNothing
)
{  }

U kunt ze ook optioneel maken, zodat u kunt detecteren of de beller er een heeft doorgegeven:

func sendBody(
    body: NSData? = nil,
    success: ((NSData) -> Void)? = nil,
    failure: ((NSData?) -> Void)? = nil
    )
{ success?(NSData()) }
sendBody(success: { _ in print("ah, yeah!") })

Ook het vermelden waard als je dit doet: als de beller de afsluitende syntaxis gebruikt, is dit de laatsteafsluiting in de lijst met argumenten. Dus je wilt dat de laatste degene is die de gebruiker waarschijnlijk wil leveren, wat waarschijnlijk de succesvolle afsluiting is:

func sendBody(
    body: NSData? = nil,
    success: ((NSData) -> Void)? = nil,
    failure: ((NSData?) -> Void)? = nil
    )
{
    if success != nil { print("passed a success closure") }
    if failure != nil { print("passed a failure closure") }
}
// this prints "passed a failure closure"
sendBody { data in
    print("which closure is this?")
}

Anders dan dit is de volgorde in de functiedeclaratie niet van belang voor de aanroeper – standaardargumenten kunnen in elke volgorde worden opgegeven.


Antwoord 2, autoriteit 10%

Je zou zoiets als dit kunnen doen,

let defaultSuccess: NSData -> Void = {
    (data: NSData) in
}
let defaultFailure: NSData? -> Void = {
    (data: NSData?) in
}
func sendBody( body: NSData? = nil, success: (data: NSData) -> Void = defaultSuccess, failure: (data: NSData?) -> Void = defaultFailure) {
}

Dan kunt u mogelijk een van deze methoden aanroepen. Let op sendBody die wordt aangeroepen met standaardparameters.

sendBody()
sendBody(body: , success: , failure: )

Je kunt ook met alle varianten aanroepen, zoals het doorgeven van slechts één van de argumenten in de bovenstaande methode, daarvoor moet je het aanroepen met de benoemde parameter.

sendBody()
sendBody(body:)
sendBody(failure: )
sendBody(success:)
sendBody(body: , success: , failure: )

Antwoord 3, autoriteit 4%

Mijn voorkeursmanier om openbare sluitingen te specificeren – in het bijzonder voltooiingssluitingen die u ergens voor later wilt opslaan – is om een ​​typealiasvoor hen te definiëren, zoals deze:

public typealias FooCompletion = (String) -> Void

Vervolgens kun je het in de openbare functie gemakkelijk als volgt optioneel maken:

var onCompletion: FooCompletion? = nil
public func foo(completion: FooCompletion? = nil) {
    // Store completion for later
    onCompletion = completion
}

De parameter completionis optioneel, dus het mag nilzijn, en de standaardwaarde is nil, wat betekent dat de beller dat niet doet moet het specificeren. Omdat u het type op meer dan één plaats gebruikt, is er ook maar één plaats om de definitie ervan te wijzigen tijdens de ontwikkeling. Bellen is ook gemakkelijk:

private func someBackgroundThing() {
    var completionString = "done"
    ...
    onCompletion?(completionString)
}

Antwoord 4, autoriteit 4%

Een standaardwaarde instellen voor een functieparameter. Swift 4 en (waarschijnlijk) 5.

func someFunction(age: Int, doSomething:@escaping () -> Void = {}){
  //do work here
  //
  doSomething()
}

Dan kunt u dit doen

someFunction(age: 18) {
  print("hello")
}
someFunction(age: 19)

Misschien moet u het trefwoord @escapingwel of niet gebruiken. Zie daarvoor Swift @escaping and Completion Handler.

Other episodes