简体   繁体   中英

Syntax of Block in Swift

I am trying to rewrite from Objective-C to Swift, I cannot work out the syntax or understand the docs

Here is a simplified example in Objective-C I wrote:

[UIView animateWithDuration:10.0 animations:^{self.navigationController.toolbar.frame = CGRectMake(0,10,0,10);}];

How do I write this in Swift?

This is the template autocomplete gives:

UIView.animateWithDuration(duration: NSTimeInterval, animations: (() -> Void))

This is the swift closure format:

{(parameter:type, parameter: type, ...) -> returntype in
    //do stuff  
}

This is what you should do:

//The animation closure will take no parameters and return void (nothing).
UIView.animateWithDuration(duration: NSTimeInterval, animations: {() -> Void in
    //Animate anything.
})

Here is the documentation for closures.

Since the expected argument types and return type to the animations argument are known the compiler can infer them without a problem. This should work (though I don't have the playground available right at the moment:

UIView.animateWithDuration(10.0, animations: {
  self.navigationController.toolbar.frame = CGRect(x:0.0, y:10.0, width:10.0, height:0.0)
})

for more info about closures see the chapter in the swift docs

note about CGRect() - the developer docs show CGRect() being used in swift code. Perhaps it requires an import?

update for comments: you can also use a trailing closure like so:

UIView.animateWithDuration(10.0) {
  self.navigationController.toolbar.frame = CGRect(x:0.0, y:10.0, width:10.0, height:0.0)
}

Following code can guide to write your own block.

class func testFunc(completion: ((list : NSArray!) -> Void)?) {
    //---  block code.
    if completion! != nil {
        completion! (list: NSArray())
    }
}

and you can call it like -

className.testFunc {
(list: NSArray!) -> Void in
}

You can basically write it in 3 identical ways:

write what to do right in the closure/code block:

UIView.animateWithDuration(10.0) {
  self.navigationController.toolbar.frame = CGRect(x:0.0, y:10.0, width:10.0, height:0.0)
}

This is also known as trailing closure ( You can only do trailing closure if the closure parameter is the last parameter)

This doesn't mean the parameter 'animations' is no longer written. It is written but just as in the format of above.


Write exactly within the lines, most developers avoid such, because it's a little buggy to write with all the parenthesis and braces.

UIView.animateWithDuration(10.0, animations: {
  self.navigationController.toolbar.frame = CGRect(x:0.0, y:10.0, width:10.0, height:0.0)
})

(Contrary to trailing closure you wrote name ie 'animations') This is known as inline closure


Write in a more modular sense

UIView.animateWithDuration(duration: NSTimeInterval, animations: animatingFunc)

func animatingFunc() {
  self.navigationController.toolbar.frame = CGRect(x:0.0, y:10.0, width:10.0, height:0.0)
}

Remember the type of the parameter 'animations' was () -> Void

Exactly as what we are doing, animatingFunc takes no parameters ie '()' and returns nothing ie 'void'

(In Swift, functions are types and can be passed in as parameters) Some might say this is more readable some might say trailing closure is...


Side note 1 You can also do nothing ( which really doesn't make sense but in many other handlers/animations/completion handlers you may not want to do anything)

UIView.animateWithDuration(duration: NSTimeInterval, animations: nil)

Side note 2

Closures becomes more interesting when you have to capture a value. See this simple demonstration. For more information about Swift closures see Apple's Documentation

How Do I Declare a Closure in Swift?

  1. As a variable:

    var closureName: (ParameterTypes) -> ReturnType

  2. As an optional variable:

    var closureName: ((ParameterTypes) -> ReturnType)?

  3. As a type alias:

    typealias ClosureType = (ParameterTypes) -> ReturnType

  4. As a constant:

    let closureName: ClosureType = { ... }

  5. As a parameter to another function:

    funcName(parameter: (ParameterTypes) -> ReturnType)

Note: if the passed-in closure is going to outlive the scope of the method, eg if you are saving it to a property, it needs to be annotated with @escaping .

  1. As an argument to a function call:

    funcName({ (ParameterTypes) -> ReturnType in statements })

  2. As a function parameter:

    array.sorted(by: { (item1: Int, item2: Int) -> Bool in return item1 < item2 })

  3. As a function parameter with implied types:

    array.sorted(by: { (item1, item2) -> Bool in return item1 < item2 })

  4. As a function parameter with implied return type:

    array.sorted(by: { (item1, item2) in return item1 < item2 })

  5. As the last function parameter:

    array.sorted { (item1, item2) in return item1 < item2 }

  6. As the last parameter, using shorthand argument names:

    array.sorted { return $0 < $1 }

  7. As the last parameter, with an implied return value:

    array.sorted { $0 < $1 }

  8. As the last parameter, as a reference to an existing function:

    array.sorted(by: <)

  9. As a function parameter with explicit capture semantics:

    array.sorted(by: { [unowned self] (item1: Int, item2: Int) -> Bool in return item1 < item2 })

  10. As a function parameter with explicit capture semantics and inferred parameters / return type:

    array.sorted(by: { [unowned self] in return $0 < $1 })

This site is not intended to be an exhaustive list of all possible uses of closures.
ref: http://goshdarnclosuresyntax.com/

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM