Входной параметр для замыкания в Swift со скобками

Я просматриваю следующий учебник по RxSwift:

http://adamborek.com/thinking-rxswift/

и возникли проблемы с пониманием следующего шаблона:

           searchBar.rx.text.orEmpty
------------> .flatMap { [spotifyClient] query in
                   return spotifyClient.rx.search(query: query)
             }.map { tracks in
                   return tracks.map(TrackRenderable.init)
             }

Этот входной параметр в квадратных скобках: [spotifyClient] query кажется мне очень странным. Я просмотрел официальную Apple документацию по замыканиям и функциям и не вижу ни одного примера таких входных параметров. В Objective C меня бы это не сильно беспокоило, но это Swift. Кто-нибудь может объяснить, что здесь означает этот параметр?


person Nikita Vlasenko    schedule 05.04.2018    source источник
comment
Это список захвата, чтобы скопировать объект в свой блок.   -  person staticVoidMan    schedule 05.04.2018


Ответы (1)


Вам нужно будет понять идею переменного захвата замыкания.

Рассмотрим этот пример:

struct Calculator {
    var a: Int
    var b: Int

    var sum: Int {
        return a + b
    }
}

Затем вы используете это как:

let calculator = Calculator(a: 3, b: 5)

// You define a closure where you will use this calculator instance
let closure = {
    // closure captures the variables that are declared prior to the declaration of the closure.
    // your calculator instance is being captured here
    // it's default variable capture
    print("The result is \(calculator.sum)")
}

closure() // Prints "The result is 8"

До сих пор все в порядке. Вы получаете ожидаемое.

Теперь представьте, что вы объявили экземпляр калькулятора как var, потому что в какой-то момент вам нужно изменить его состояние. Это тот случай, когда возникает сложность. Смотреть:

var calculator = Calculator(a: 3, b: 5)

let closure = {
    print("The result is \(calculator.sum)")
}

// You change the state of your calculator instance anytime before the closure gets executed
calculator.b = 20
// When the closure actually executes, you will be affected by any changes outside the closure 
closure() // Prints "The result is 23"

Таким образом, захват переменных по умолчанию на самом деле не помогает вам, а создает проблемы в вашем случае.


Если вы хотите предотвратить такое поведение и вывести 8, даже если свойства изменяются после их захвата внутри замыкания, мы можем явно захватить переменную с помощью списка захвата< /сильный> вот так:

// [calculator] is your capture list
let closure = { [calculator] in
    print("The result is \(calculator.sum)")
}
// change anything with calculator instance
calculator.b = 20
// execute the closure
closure() // Prints "The result is 8"

Capture List сохраняет неизменяемую копию переменных. Благодаря этой копии дальнейшие изменения в калькуляторе вне замыкания не повлияют на замыкание.

Вы можете захватывать несколько переменных одновременно, поэтому это называется Список захвата. Пример:

let closure = { [variable1, variable2, variable3] in
    print(variable1)
    print(variable2)
    print(variable3)
}

Я рекомендую вам прочитать эту статью Захват значений в Swift Closures.



Теперь в вашем случае spotifyClient является экземпляром класса, который может отвечать за вызовы API. В этом экземпляре могут потребоваться некоторые изменения для вызова различных API. Итак, чтобы предотвратить влияние любых изменений на spotifyClient вне этого замыкания, вы записываете этот экземпляр в Список захвата.



Список захвата против списка параметров:

Вы путаете список параметров со списком захвата. Общий синтаксис:

{ [capture list] (parameter list) in
    ...
    ...
}

Теперь взгляните на модифицированную версию приведенного выше примера:

let closure: (String)-> Void = { [calculator] stringParameter in // When using single parameter, you can always omit the () parentheses
    print("\(stringParameter). The result is \(calculator.sum)")
}

// change anything with calculator instance
calculator.b = 20
// execute the closure
closure("Hey") // Prints "Hey. The result is 8"
person nayem    schedule 05.04.2018
comment
Хорошо, но что там делает параметр «запрос»? Это второй параметр? Почему нет запятой? - person Nikita Vlasenko; 05.04.2018
comment
Ваш spotifyClient является одним из элементов списка захвата. А query - это параметр. Они не одинаковы. Смотрите мою последнюю правку. - person nayem; 05.04.2018