How to create local scopes in Swift?

Swift

Swift Problem Overview


I'm regularly using local scopes in Objective-C to make naming clearer.

{
    UILabel *label = [[UILabel alloc] init];
    [self addSubview:label];
    self.titleLabel = label;
}

I am trying to rewrite this code in Swift like this:

{
    let label = UILabel()
    self.addSubview(label)
    self.titleLabel = label
}

This gives me get the following error:

Error: Braced block of statements is an unused closure.

So how can I create a local scope in Swift?

Swift Solutions


Solution 1 - Swift

Update: In Swift 2.0, you just use the do keyword:

do {
    let label = UILabel()
    self.addSubview(label)
    self.titleLabel = label
}


This was true for Swift pre-2.0:

You can define something similar to this:

func locally(@noescape work: () -> ()) {
    work()
}

And then use such a locally block as follows:

locally {
    let g = 42
    println(g)
}

(Inspired by locally in Scala's Predef object.)

Solution 2 - Swift

As of Swift 2, you can create a local scope with the do-statement:

do {
    let x = 7
    print(x)
}
print(x) // error: use of unresolved identifier 'x'

The main use-case however seems to be error-handling with do-try-catch, as documented in "Error Handling" in "The Swift Programming Language", for example:

do {
    let jsonObj = try NSJSONSerialization.JSONObjectWithData(jsonData, options: [])
    // success, do something with `jsonObj`...

} catch let error as NSError {
    // failure
    print("Invalid JSON data: \(error.localizedDescription)")
}

Solution 3 - Swift

I don't think it is possible.

At least a grammar that is in the book that is available in iBooks store does not mention it.

You could do this,

if (true) {
    let a = 4
}

but I think, it is a bad practice.

Solution 4 - Swift

As noted in comments, anonymous nested scopes in C are often a sign that you could be writing better code. For example, instead of simply doing work in a nested scope that ultimately sets self.titleLabel, you could you could instead make that assignment the result of evaluating an inline closure:

self.titleLabel = {
    let label = UILabel()
    label.text = "some text"
    // ... set other properties ...
    self.addSubview(label)
    return label
}()

This not only keeps label as a nice short name that's scoped only to the chunk of code that creates and configures one, but keeps that chunk of code associated with the property it's creating a value for. And it's more modular, in that you could replace the whole closure with a call to some other label-creating function should it ever become useful to factor out that code.

If you find yourself doing this sort of thing frequently, you could try making a generic function that lets you cut your construction code down to this:

self.titleLabel = makeSubview(UILabel()) { label in
    label.text = "some text"
    // other label properties
}

But I'll leave defining such a function as an exercise for the reader. ;)


As noted in Jean-Philippe Pellet's answer, in Swift 2.0 and later the do construct is the explicitly language-provided way to do this. (And the function-based solution he suggests is a decent option for anyone still using Swift 1.x.)

Another Swift 1.x solution — without defining a new function — is to (explicitly) throw away the result of an immediately-executed closure:

 _ = {
     print("foo")
 }() 

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionAntonView Question on Stackoverflow
Solution 1 - SwiftJean-Philippe PelletView Answer on Stackoverflow
Solution 2 - SwiftMartin RView Answer on Stackoverflow
Solution 3 - SwiftTomáš LinhartView Answer on Stackoverflow
Solution 4 - SwiftricksterView Answer on Stackoverflow