14

Having a hard time figuring out how to properly declare/use blocks with swift. What would be the swift equivalent of the following code?

Thanks.

^(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!");
}
Brandon Foo
  • 175
  • 1
  • 1
  • 7
  • possible duplicate of [How does Apple's new programming language Swift handle blocks and asynchronous requests?](http://stackoverflow.com/questions/24006398/how-does-apples-new-programming-language-swift-handle-blocks-and-asynchronous-r) – NobodyNada Jun 03 '14 at 23:16

6 Answers6

15

The equivalent of Objective-C blocks are swift closures, so it would go as follows

{ (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!");
  }
}
Gabriele Petronella
  • 106,943
  • 21
  • 217
  • 235
7

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:

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

IMO it's more beautiful than in ObjC

Francescu
  • 16,974
  • 6
  • 49
  • 60
  • Hey @Fran .. you may be able to provide a more up-to-date answer to THIS question ... http://stackoverflow.com/a/20760583/294884 thanks! you're pretty much it for "expert in SWIFT blocks..." :) – Fattie Jun 17 '14 at 09:37
  • 1
    Thanks you. I'll send this answer just for information even if the question is for objC. – Francescu Jun 17 '14 at 13:40
  • ...and IMHO, if you'd used the `__FUNCTION__` that would have been more beautiful. – holex Jun 08 '15 at 15:02
2

Critically, if user can be nil then it must be declared as an Optional. Thus:

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

noting that the type for user includes ? to indicate that user is an optional argument (either nil or of type PFUser).

Other answers, that don't use an Optional, won't even compile.

GoZoner
  • 67,920
  • 20
  • 95
  • 145
2

See if this works for you. It's crazy trying to learn this on day two.

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

If you want to store block in a variable and call it later, check this answer

Community
  • 1
  • 1
Ashok
  • 5,585
  • 5
  • 52
  • 80
0

// define it

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

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

// use it

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

    print("timeSpent: '\(timeSpent) ms'")
Klajd Deda
  • 355
  • 2
  • 7