В моем 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]
?
Если self может быть nil в закрытии, используйте [слабый я].
Если self никогда не будет равным нулю в использовании закрытия, используйте [unowned self].
Если он сбой, когда вы используете [unowned self], я бы догадался, что в какой-то момент этого замыкания нет никого, поэтому вам нужно было пойти с [слабым я].
Мне очень понравился весь раздел из руководства по использованию strong, слабый и unowned в закрытии:
Примечание. Я использовал термин закрытие вместо block, который является новым термином Swift:
Разница между блоком (Objective C) и закрытием (Swift) в ios
Поместите [unowned self]
до (text: String)...
в ваше закрытие. Это называется списком захвата и помещает инструкции владельца на символы, зафиксированные в закрытии.
Используйте Список захвата
Определение списка захватов
Каждый элемент в списке захвата представляет собой спаривание слабых или незанятых ключевое слово со ссылкой на экземпляр класса (например, 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
}
РЕДАКТИРОВАНИЕ: Как прокомментировал @tim-vermeulen, Крис Латтнер сказал в пятницу 22 января 19:51:29 CST 2016, этот трюк не должен использоваться на себе, поэтому, пожалуйста, не используйте его. Проверьте информацию о не выходящих замыканиях и ответ списка захвата от @gbk.
Для тех, кто использует [слабое "я" в списке захвата, обратите внимание, что "я" может быть нулевым, поэтому первое, что я делаю, это проверяю с помощью выражения охранника
guard let 'self' = self else {
return
}
self.doSomething()
Если вам интересно, какие кавычки находятся вокруг self
, то вы можете использовать самость внутри замыкания, не меняя имя на "слабый" или что-то еще.
PS: Так как у меня есть некоторые повышающие голоса, я хотел бы рекомендовать чтение о не экранирующих закрытиях. TL; DR Большинство методов в конце вызывают закрытие, переданное аргументом, если это так, вы можете использовать @noescape в аргументе закрытия и можете неявно ссылаться на себя внутри замыкания.
РЕДАКТИРОВАТЬ: Удален трюк "Я"
Поскольку решение 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) }
Вы можете использовать [слабый self] или [unowned self] в списке захвата до ваших параметров блока. Список захвата - необязательный синтаксис.
[unowned self]
работает хорошо, потому что ячейка никогда не будет равна нулю. В противном случае вы можете использовать [weak self]
_ = { [weak self] value in
guard let strongSelf = self else { return }
print(strongSelf) // will never be nil
}()
strongSelf
явно объясняет переменные, означающие / побочный эффект, что хорошо, если код имеет более продолжительный характер. цените ваше мнение, хотя, не знал, что C ++ использовал такие фразы.
Swift 4.2
let closure = { [weak self] (_ parameter:Int) in
guard let self = self else { return }
self.method(parameter)
}
Если вы терпите крах, вы, вероятно, нуждаетесь в [слабом я]
Я предполагаю, что создаваемый вами блок каким-то образом все еще подключен.
Создайте prepareForReuse и попробуйте очистить блок onTextViewEditClosure внутри этого.
func prepareForResuse() {
onTextViewEditClosure = nil
textView.delegate = nil
}
Смотрите, предотвращает ли это сбой. (Это просто догадка).