Как правильно управлять слабым я в быстрых блоках с аргументами

В моем TextViewTableViewCell у меня есть переменная, чтобы отслеживать блок и метод configure, где блок передан и назначен.
Вот мой класс TextViewTableViewCell:

//
//  TextViewTableViewCell.swift
//

import UIKit

class TextViewTableViewCell: UITableViewCell, UITextViewDelegate {

    @IBOutlet var textView : UITextView

    var onTextViewEditClosure : ((text : String) -> Void)?

    func configure(#text: String?, onTextEdit : ((text : String) -> Void)) {
        onTextViewEditClosure = onTextEdit
        textView.delegate = self
        textView.text = text
    }

    // #pragma mark - Text View Delegate

    func textViewDidEndEditing(textView: UITextView!) {
        if onTextViewEditClosure {
            onTextViewEditClosure!(text: textView.text)
        }
    }
}

Когда я использую метод configure в моем методе cellForRowAtIndexPath, как правильно использовать слабое я в блоке, который я передаю.
Вот что я имею без слабой самости:

let myCell = tableView.dequeueReusableCellWithIdentifier(textViewCellIdenfitier) as TextViewTableViewCell
myCell.configure(text: body, onTextEdit: {(text: String) in
   // THIS SELF NEEDS TO BE WEAK  
   self.body = text
})
cell = bodyCell

ОБНОВЛЕНИЕ. У меня есть следующее: [weak self]:

let myCell = tableView.dequeueReusableCellWithIdentifier(textViewCellIdenfitier) as TextViewTableViewCell
myCell.configure(text: body, onTextEdit: {[weak self] (text: String) in
        if let strongSelf = self {
             strongSelf.body = text
        }
})
cell = myCell

Когда я делаю [unowned self] вместо [weak self] и вынимаю инструкцию if, приложение отключается. Любые идеи о том, как это должно работать с [unowned self]?

Ответ 1

Если self может быть nil в закрытии, используйте [слабый я].

Если self никогда не будет равным нулю в использовании закрытия, используйте [unowned self].

Если он сбой, когда вы используете [unowned self], я бы догадался, что в какой-то момент этого замыкания нет никого, поэтому вам нужно было пойти с [слабым я].

Мне очень понравился весь раздел из руководства по использованию strong, слабый и unowned в закрытии:

https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/AutomaticReferenceCounting.html

Примечание. Я использовал термин закрытие вместо block, который является новым термином Swift:

Разница между блоком (Objective C) и закрытием (Swift) в ios

Ответ 2

Поместите [unowned self] до (text: String)... в ваше закрытие. Это называется списком захвата и помещает инструкции владельца на символы, зафиксированные в закрытии.

Ответ 3

Используйте Список захвата

Определение списка захватов

Каждый элемент в списке захвата представляет собой спаривание слабых или незанятых ключевое слово со ссылкой на экземпляр класса (например, self) или переменная, инициализированная некоторым значением (например, delegate = self.delegate!). Эти пары записываются в пределах пары квадратов скобки, разделенные запятыми.

Поместите список захвата до списка параметров закрытия и возврата если они предоставлены:

lazy var someClosure: (Int, String) -> String = {
    [unowned self, weak delegate = self.delegate!] (index: Int, stringToProcess: String) -> String in
    // closure body goes here 
} 

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

lazy var someClosure: Void -> String = {
    [unowned self, weak delegate = self.delegate!] in
    // closure body goes here
}

дополнительные объяснения

Ответ 4

** ИЗМЕНЕНО для Swift 4.2:

Как прокомментировал @Koen, swift 4.2 позволяет:

guard let self = self else {
   return // Could not get a strong reference for self :'(
}

// Now self is a strong reference
self.doSomething()

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

РЕДАКТИРОВАНИЕ: Как прокомментировал @tim-vermeulen, Крис Латтнер сказал в пятницу 22 января 19:51:29 CST 2016, этот трюк не должен использоваться на себе, поэтому, пожалуйста, не используйте его. Проверьте информацию о не выходящих замыканиях и ответ списка захвата от @gbk. **

Для тех, кто использует [слабое я] в списке захвата, обратите внимание, что self может быть нулем, поэтому первое, что я делаю, это проверяю с помощью оператора guard

guard let 'self' = self else {
   return
}
self.doSomething()

Если вам интересно, какие кавычки находятся вокруг self это способ использовать себя внутри замыкания, не меняя имя на "слабый" или что-то еще.

Ответ 5

РЕДАКТИРОВАТЬ: Ссылка на обновленное решение от LightMan

Смотрите решение LightMan. До сих пор я использовал:

input.action = { [weak self] value in
    guard let this = self else { return }
    this.someCall(value) // 'this' isn't nil
}

Или же:

input.action = { [weak self] value in
    self?.someCall(value) // call is done if self isn't nil
}

Обычно вам не нужно указывать тип параметра, если он выводится.

Вы можете вообще опустить параметр, если его нет, или если в закрытии вы называете его $0:

input.action = { [weak self] in
    self?.someCall($0) // call is done if self isn't nil
}

Просто для полноты картины; если вы передаете замыкание функции, а параметр не @escaping, вам не нужно weak self:

[1,2,3,4,5].forEach { self.someCall($0) }

Ответ 7

Начиная с версии 4.2 🔸 мы можем сделать:

_ = { [weak self] value in
    guard let self = self else { return }
    print(self) //👈 will never be nil
}()

Ответ 8

Вы можете использовать [слабый self] или [unowned self] в списке захвата до ваших параметров блока. Список захвата - необязательный синтаксис.

[unowned self] работает хорошо, потому что ячейка никогда не будет равна нулю. В противном случае вы можете использовать [weak self]

Ответ 9

Если вы терпите крах, вы, вероятно, нуждаетесь в [слабом я]

Я предполагаю, что создаваемый вами блок каким-то образом все еще подключен.

Создайте prepareForReuse и попробуйте очистить блок onTextViewEditClosure внутри этого.

func prepareForResuse() {
   onTextViewEditClosure = nil
   textView.delegate = nil
}

Смотрите, предотвращает ли это сбой. (Это просто догадка).