Подтвердить что ты не робот

Как создать локальные области в Swift?

Я регулярно использую локальные области в Objective-C, чтобы сделать именование более понятным.

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

Я пытаюсь переписать этот код в Swift следующим образом:

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

Это дает мне следующую ошибку:

Error: Braced block of statements is an unused closure.

Итак, как я могу создать локальную область в Swift?

4b9b3361

Ответ 1

Обновление: В Swift 2.0 вы просто используете ключевое слово do:

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

Это верно для Swift pre-2.0:

Вы можете определить что-то похожее на это:

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

И затем используйте такой блок locally следующим образом:

locally {
    let g = 42
    println(g)
}

(Вдохновленный locally в Scala Predef объект.)

Ответ 2

Я не думаю, что это возможно.

По крайней мере, грамматика, содержащаяся в книге, доступной в магазине iBooks, не упоминает об этом.

Вы можете сделать это,

if (true) {
    let a = 4
}

но я думаю, что это плохая практика.

Ответ 3

Как отмечено в комментариях, анонимные вложенные области на C часто являются признаком того, что вы могли бы писать лучший код. Например, вместо простого выполнения работы во вложенной области, которая в конечном итоге устанавливает self.titleLabel, вы можете вы могли бы вместо этого присвоить результат оценки встроенного закрытия:

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

Это не только сохраняет label как красивое короткое имя, которое относится только к фрагменту кода, который создает и настраивает его, но сохраняет этот кусок кода, связанный с свойством, для которого он создает значение. И он более модульный, поскольку вы могли бы заменить все закрытие вызовом какой-либо другой функции создания ярлыков, если бы когда-нибудь стало полезно откорректировать этот код.

Если вы часто это делаете, вы можете попробовать создать общую функцию, которая позволит вам сократить свой код построения до этого:

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

Но я оставлю определение такой функции, как упражнение для читателя.;)


Как указано в ответ Jean-Philippe Pellet, в Swift 2.0, а позже конструкция do - это явно предоставленный языком способ сделать это. (И функциональное решение, которое он предлагает, является достойным вариантом для тех, кто все еще использует Swift 1.x.)

Другое решение Swift 1.x - без определения новой функции - заключается в (явно) выкидывать результат немедленно выполненного закрытия:

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

Ответ 4

В Swift 2 вы можете создать локальную область с do -statement:

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

Основным вариантом использования, однако, является обработка ошибок с помощью do-try-catch, как описано в "Обработка ошибок" в "Язык быстрого языка" , например:

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

Ответ 5

Что я делаю, это определить анонимную функцию и выполнить ее.

// ... preceding code ...
// ... might need semicolon here;
{
    () -> () in
    // ... this is a local scope ...
}()
// ... following code ...

Возможно, вам придется положить точку с запятой в конце предыдущей строки, чтобы Swift не думал, что это "закрывающее закрытие". Вы можете даже разместить эту точку с запятой в одной строке непосредственно перед открытием фигурной скобки. Итак, реализуя исходный код OP:

;{
    () -> () in
    let label = UILabel()
    self.addSubview(label)
    self.titleLabel = label
}()

EDIT Впоследствии я обнаружил, что вместо этого возвращаюсь if true {...}. Однако, как указывает Мартин, в Swift 2 do {...} будет разрешен как официальный способ определения произвольной области видимости. Таким образом, решение проблемы будет приятно.