Tenho um closure em um section provider em um inicializador de fonte de dados diffable onde estou definindo a variável checkCellView
de dentro do closure. Quando chamo o closure de dentro switchCheckSelectionFunc()
da CheckCellView
célula errada, ele acaba sendo selecionado. Como posso consertar isso?
class QuestionnaireViewController: UIViewController {
var checkCellView: CheckCellView? {
didSet {
if checkCellView != nil {
print("type of closure,", type(of: checkCellView!.switchCheckSelection))
} else {
}
}
}
func configureDataSource() {
dataSource = CustomTableViewDiffableDataSource(tableView: tableView, cellProvider: { [self] tableView, indexPath, formItem in
// print("section,", indexPath.section)
self.checkCellView?.switchCheckSelection = { checkIsSelected in
if checkIsSelected {
checkCellView?.checkImageView.image = UIImage(named: "check-box-selected")!
} else {
checkCellView?.checkImageView.image = UIImage(named: "check-box-deselected")!
}
}
switch formItem {
case .name(let name):
let cell = tableView.dequeueReusableCell(withIdentifier: PatientInfoCell.reuseID, for: indexPath) as! PatientInfoCell
cell.configure(title: "First Name")
return cell
case .lastName(let lastName):
let cell = tableView.dequeueReusableCell(withIdentifier: PatientInfoCell.reuseID) as! PatientInfoCell
cell.configure(title: "Last Name")
return cell
case .age(let age):
let cell = tableView.dequeueReusableCell(withIdentifier: PatientInfoCell.reuseID) as! PatientInfoCell
cell.configure(title: "Age")
return cell
case .gender(let gender):
let cell = tableView.dequeueReusableCell(withIdentifier: GenderCell.reuseID) as! GenderCell
cell.titleView.text = "Gender"
cell.femaleIcon.image = UIImage(named: "female-icon-deselected")!
cell.switchFemaleIconTapped = { isSelected in
if isSelected {
cell.femaleIcon.image = UIImage(named: "female-icon-selected")!
} else {
cell.femaleIcon.image = UIImage(named: "female-icon-deselected")!
}
}
cell.maleIcon.image = UIImage(named: "male-icon-deselected")!
cell.switchMaleIconTapped = {
if $0 {
cell.maleIcon.image = UIImage(named: "male-icon-selected")!
} else {
cell.maleIcon.image = UIImage(named: "male-icon-deselected")!
}
}
return cell
case .indwellingCardiacDeviceOrProsthesis(let bool):
checkCellView = tableView.dequeueReusableCell(withIdentifier: CheckCellView.reuseID, for: indexPath) as? CheckCellView
checkCellView?.checkImageView.image = UIImage(named: "check-box-deselected")!
checkCellView?.switchCheckSelection = { checkIsSelected in
if checkIsSelected {
checkCellView?.checkImageView.image = UIImage(named: "check-box-selected")!
} else {
checkCellView?.checkImageView.image = UIImage(named: "check-box-deselected")!
}
}
return checkCellView
case .predisposingHeartCondition(let bool):
checkCellView = tableView.dequeueReusableCell(withIdentifier: CheckCellView.reuseID, for: indexPath) as? CheckCellView
checkCellView?.checkImageView.image = UIImage(named: "check-box-deselected")!
return checkCellView
case .intravenousDrugUse(let bool):
checkCellView = tableView.dequeueReusableCell(withIdentifier: CheckCellView.reuseID, for: indexPath) as? CheckCellView
checkCellView?.checkImageView.image = UIImage(named: "check-box-deselected")!
return checkCellView
case .cardiacStructuralDisorder(let bool):
checkCellView = tableView.dequeueReusableCell(withIdentifier: CheckCellView.reuseID, for: indexPath) as? CheckCellView
checkCellView?.checkImageView.image = UIImage(named: "check-box-deselected")!
return checkCellView
case .diabetic(let bool):
checkCellView = tableView.dequeueReusableCell(withIdentifier: CheckCellView.reuseID, for: indexPath) as? CheckCellView
checkCellView?.checkImageView.image = UIImage(named: "check-box-deselected")!
return checkCellView
}
})
}
}
class CheckCellView: UITableViewCell {
var titleView: UILabel = UILabel()
var checkImageView: UIImageView = UIImageView()
static var reuseID = "check-cell-reuseID"
required init?(coder: NSCoder) {
super.init(coder: coder)
}
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
setUp()
}
var switchCheckSelection: ((_ isSelected: Bool) -> Void)?
var checkIsSelected: Bool = false
func setUp() {
checkImageView.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(switchCheckSelectionFunc)))
checkImageView.isUserInteractionEnabled = true
let stackView = UIStackView(arrangedSubviews: [
titleView,
checkImageView
])
stackView.axis = .horizontal
stackView.distribution = .fill
stackView.translatesAutoresizingMaskIntoConstraints = false
contentView.addSubview(stackView)
NSLayoutConstraint.activate([
stackView.leadingAnchor.constraint(equalTo: leadingAnchor),
stackView.trailingAnchor.constraint(equalTo: trailingAnchor),
stackView.topAnchor.constraint(equalTo: topAnchor)
])
}
@objc func switchCheckSelectionFunc() {
checkIsSelected.toggle()
switchCheckSelection?(checkIsSelected)
}
func applySnapshot() {
guard case let .questionnaireData(formData) = data,
let formData = formData else {
return
}
var snapshot = NSDiffableDataSourceSnapshot<Section, FormItem>()
snapshot.appendSections(Section.allCases)
snapshot.appendItems(formData.patientInfoData, toSection: .patientInformation)
snapshot.appendItems(formData.checkAllThatApplyData, toSection: .checkAllThatApply)
dataSource.apply(snapshot, animatingDifferences: true)
}
}
Quando um fechamento é declarado, ele "captura" os valores das variáveis às quais ele faz referência.
No seu caso, seus fechamentos se parecem com
Há duas variáveis usadas neste fechamento:
checkIsSelected
, que é o argumento passado para o fechamento, echeckCellView
, que é a célula que você deseja modificar.Agora
checkCellView
é uma propriedade do seu controlador de visualização. Se reescrevermos seu fechamento para adicionar explicitamente oself.
que você omitiu quando se referiu acheckCellView
você verá a causa do seu problema:Você pensou que, por ter atribuído o closure em seu
cellForRowAt
, o closure capturaria o valor atual decheckCellView
, mas o que é realmente capturado éself
, comself.checkCellView
sendo avaliado quando o closure é executado. Como você reatribuiself.checkCellView
cada vez que seu closure de fonte de dados diferenciável é chamado, é improvável queself.checkCellView
realmente se refira à célula desejada.Uma solução seria usar uma variável local no fechamento da sua fonte de dados diferenciável, como você faz com sua célula de gênero:
Algo como:
Mas eu provavelmente mudaria
CheckCellView
para que ele tivesse apenas duasUImage
propriedades, uma para selecionado e uma para des-selecionado e eliminaria o fechamento completamente. É apenas código repetido.