Правильно ли использовать `[слабое я]` в быстром закрытии? - PullRequest
0 голосов
/ 16 февраля 2019

Я всегда использую [weak self] в быстром закрытии, чтобы предотвратить референсный цикл.Вот код ниже, это правильный путь?

someTask(completion: {[weak self] (result) in
        if self == nil {  
            return
        }

        //is it safe when reach here? 

        self!.xxx = yyy
        self!.doLongTermWork()
        self!.finish()  //will crash when self is nil?
    })

Слабое «я» не удерживает сильную власть над экземпляром.Итак, когда self.doLongTermWork(), будет ли self снова установлен на nil где-нибудь еще?

Ответы [ 3 ]

0 голосов
/ 16 февраля 2019

Вы можете использовать это как Swift 4.2

someTask(completion: {[weak self] (result) in
    guard let self == self { return }

    //it safe when reach here always

    self.xxx = yyy
    self.doLongTermWork()
    self.finish()
})
0 голосов
/ 16 февраля 2019

Ваша модель имеет состояние гонки.Если self был освобожден в то же самое время, когда выполнялось закрытие вашего обработчика завершения, это может привести к сбою.Как правило, избегайте использования оператора ! принудительного развертывания, если можете.

  1. Я бы склонился к шаблону guard «ранний выход» (сокращение вложенных скобок, созданиекод легче читать).Стандартное решение Swift 4.2:

    someTask { [weak self] result in
        guard let self = self else { return }
    
        self.xxx = yyy
        self.doLongTermWork()
        self.finish()
    }
    
  2. До Swift 4.2, в котором реализовано SE-0079 , мы должны были бы сделать что-то вроде:

    someTask { [weak self] result in
        guard let strongSelf = self else { return }
    
        strongSelf.xxx = yyy
        strongSelf.doLongTermWork()
        strongSelf.finish()
    }
    

    Вы можете понять, почему мы предпочитаем улучшение Swift 4.2, поскольку этот синтаксис strongSelf не элегантен.

  3. Другая очевидная альтернатива - просто:

    someTask { [weak self] result in
        self?.xxx = yyy
        self?.doLongTermWork()
        self?.finish()
    }
    

    Иногда вам нужен «слабый я - сильный танец сам» (первые две альтернативы), но, похоже, это не так.Этого, вероятно, достаточно.

Существуют и другие сценарии / крайние случаи, которые можно рассмотреть, но это основные подходы.

0 голосов
/ 16 февраля 2019

Вы сказали:

someTask(completion: {[weak self] (result) in
    if self == nil {  
        return
    }
    //is it safe when reach here? 
    self!.xxx = yyy
})

Нет!Вы не сохранили self, поэтому теоретически оно может стать nil в любое время во время выполнения закрытия.Это, вероятно, не будет, но «вероятно» не достаточно хорош.А восклицательные знаки - это всегда приглашение к краху.

Сделайте слабый-сильный танец и сделайте это правильно:

someTask(completion: {[weak self] (result) in
    if let self = self {  // or let `self` before Swift 4
        // here, self is safe, because you made the reference strong again
        self.xxx = yyy
    }
})
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...