Назад к вопросам
Middle
148
questionbank

Расскажи о capture list в Swift.

Sobes Copilot

Получайте ответы в реальном времени

Ответ от нейросети

sobes.tech AI

Capture list в Swift используется для явного управления захватом переменных замыканиями (closures). Это позволяет избежать сильных циклов ссылок, особенно при работе с self в замыканиях, которые используются внутри классов. Основные типы захвата: weak и unowned.

Тип захвата Описание Когда использовать
weak Захватывает переменную как опционал, не увеличивая счетчик ссылок. Её значение может стать nil. Когда объект замыкания может пережить захватываемый объект.
unowned Захватывает переменную без увеличения счетчика ссылок, но считается, что захватываемый объект будет жив, пока существует замыкание. Не опционал. Когда объект замыкания и захватываемый объект имеют одинаковое время жизни, и захватываемый объект не будет nil до завершения замыкания.

Синтаксис capture list:

{ [capture list] (parameters) -> returnType in
    // code
}

Пример использования weak self:

class MyClass {
    var value = 0

    func doSomethingLater() {
        DispatchQueue.main.asyncAfter(deadline: .now() + 1) { [weak self] in
            guard let self = self else { return } // Проверка на nil
            self.value += 1
            print("Value is now \(self.value)")
        }
    }
}

Пример использования unowned self:

class ViewController: UIViewController {
    var button: UIButton!

    override func viewDidLoad() {
        super.viewDidLoad()
        button = UIButton(type: .system)
        button.addTarget(self, action: #selector(buttonTapped), for: .touchUpInside)
    }

    @objc func buttonTapped() {
        // unowned self не требуется в этом случае, так как button существует, пока существует ViewController.
        // Но если бы замыкание могло пережить ViewController, unowned мог бы быть уместен при
        // уверенности, что self не станет nil.
        let action = { [unowned self] in
             self.view.backgroundColor = .blue
        }
        action()
    }
}

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

func createIncrementer(initialValue: Int) -> () -> Int {
    var currentValue = initialValue
    return { [initialValue] in // Захватываем initialValue по значению
        currentValue += 1
        print("Initial value was \(initialValue)") // initialValue сохраняет свое значение
        return currentValue
    }
}

let incrementer = createIncrementer(initialValue: 5)
print(incrementer()) // Output: Initial value was 5, then 6
print(incrementer()) // Output: Initial value was 5, then 7