web-dev-qa-db-fra.com

Comment déclarer un bloc avec des arguments en swift?

Avoir du mal à comprendre comment déclarer/utiliser correctement des blocs avec Swift. Quel serait l'équivalent Swift du code suivant? 

Merci.

^(PFUser *user, NSError *error) {
if (!user) {
    NSLog(@"Uh oh. The user cancelled the Facebook login.");
} else if (user.isNew) {
    NSLog(@"User signed up and logged in through Facebook!");
} else {
    NSLog(@"User logged in through Facebook!");
}
12
Brandon Foo

L'équivalent des blocs Objective-C sont les fermetures Swift, donc ça irait comme suit

{ (user: PFUser, error: NSError) 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!");
  }
}
14

Vous avez plusieurs possibilités pour passer un bloc équivalent à fonctionner dans Swift. 

J'ai trouvé trois.

Pour comprendre cela, je vous suggère de tester dans le terrain de jeu ce petit morceau de 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)

Mise à jour: Il y a 2 cas spéciaux à la fonction Anonyme.

La première est que la signature de la fonction peut être déduite afin que vous n'ayez pas à la réécrire. 

let resultShortAnon = test({return "ANON_" + $0 + "__ANON" })

Le deuxième cas spécial ne fonctionne que si le bloc est le dernier argument, il s'appelle fin de la fermeture

Voici un exemple (fusionné avec une signature inférée pour montrer la puissance Swift)

let resultTrailingClosure = test { return "TRAILCLOS_" + $0 + "__TRAILCLOS" }

Finalement:

En utilisant tout ce pouvoir, je mélangerais fin de clôture et inférence de type (avec nommage pour la lisibilité)

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!")
    }
}

OMI c'est plus beau que dans ObjC

7
Francescu

Si vous voulez stocker un bloc dans une variable et l'appeler plus tard, cochez cette answer

2
Ashok Kumar S

De manière critique, si user peut être nil, alors il doit être déclaré comme facultatif. Ainsi: 

{ (user: PFUser?, error: NSError) -> {} in
         if (nil == user) ...
    }

notant que le type pour user inclut ? pour indiquer que user est un argument optional (soit nil ou de type PFUser).

D'autres réponses, qui n'utilisent pas un optionnel, ne seront même pas compilées.

2
GoZoner

Voyez si cela fonctionne pour vous. C'est fou d'essayer d'apprendre cela le deuxième jour.

let afterSignInAttempt: (PFUser?, NSError) -> Void = { user, error in
    if(!user){
      NSLog("Uh oh.")
    } else {
      user.isNew ? NSLog("Signed up") : NSLog("User Logged in")
    }
}
2
Dan Hixon

// Définissez-le

class IDDBlockTime {
    // return time elapsed in milliseconds
    //
    static func timeSpent(_ block: (Void) -> Void) -> TimeInterval {
        let methodStart = Date()

        block()
        return Date().timeIntervalSince(methodStart) * 1000.0
    }
}

// utilise le

    let timeSpent = IDDBlockTime.timeSpent {
        // lines of code you want to measure
        //
        self.doSomethig()
    }

    print("timeSpent: '\(timeSpent) ms'")
0
Klajd Deda