I get crash logs for users with iOS14. Can I do anything about it, or should I wait till iOS14 is officially there?
Here is myCustomTableViewCell with a textField:
class TextTVCell: UITableViewCell, UITextFieldDelegate {
weak var delegate: TextTVCellDelegate?
weak var textField: UITextField? = { // I have to make it optional because of weak reference
let textField = UITextField()
textField.translatesAutoresizingMaskIntoConstraints = false
return textField
}()
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
setupSubviews()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
private func setupSubviews() {
contentView.addSubview(textField!)
......... // constraints, ...
}
Force unwrap causes the crash on any Device with iOS14. Below it works just fine.
Here is my crash log:
Incident Identifier: AB559313-AD92-4B3A-AA90-97AE47315DEF
Hardware Model: iPhone9,4
Process: FormaleBriefe [6654]
Path: /private/var/containers/Bundle/Application/798B5135-DEB8-451D-858F-AE9FA47F6C7B/FormaleBriefe.app/FormaleBriefe
Identifier: frugalResolution.Briefe
Version: 5 (2.2.2)
AppStoreTools: 11E707
AppVariant: 1:iPhone9,4:13
Code Type: ARM-64 (Native)
Role: Foreground
Parent Process: launchd [1]
Coalition: frugalResolution.Briefe [1134]
Date/Time: 2020-08-02 22:52:50.5708 +0200
Launch Time: 2020-08-02 22:52:48.3752 +0200
OS Version: iPhone OS 14.0 (18A5332f)
Release Type: Beta
Baseband Version: 4.50.04
Report Version: 104
Exception Type: EXC_BREAKPOINT (SIGTRAP)
Exception Codes: 0x0000000000000001, 0x0000000104fac2ac
Termination Signal: Trace/BPT trap: 5
Termination Reason: Namespace SIGNAL, Code 0x5
Terminating Process: exc handler [6654]
Triggered by Thread: 0
Thread 0 name:
Thread 0 Crashed:
0 FormaleBriefe 0x0000000104fac2ac TextTVCell.setupSubviews() + 3800 (TextTVCell.swift:41)
1 FormaleBriefe 0x0000000104fab458 TextTVCell.setupSubviews() + 132 (TextTVCell.swift:0)
2 FormaleBriefe 0x0000000104facb98 specialized TextTVCell.init(style:reuseIdentifier:) + 296 (TextTVCell.swift:32)
3 FormaleBriefe 0x0000000104fab374 @objc TextTVCell.init(style:reuseIdentifier:) + 72 (<compiler-generated>:0)
4 UIKitCore 0x000000019b63f448 -[UITableView _dequeueReusableViewOfType:withIdentifier:] + 532 (UITableView.m:8843)
5 FormaleBriefe 0x0000000104f8ca34 LetterWriterVC.tableView(_:cellForRowAt:) + 1504 (LetterWriterVC.swift:555)
6 FormaleBriefe 0x0000000104f8d6bc @objc
Your code was always an antipattern (aka wrong). A simple test will display the problem with pattern. I'll use a view controller:
We run the app, and the console prints
nil
. And you can easily see why. At some point, thetextField
instance property is initialized, so the closure runs and a text field is returned and assigned to thetextField
. But that reference isweak
! That means: do not hold on to me. So the instance property doesn't hold on to the text field; it drops it, the text field goes out of existence, and the reference is replaced bynil
.Simple solution: don't do that! It's an antipattern, as I said. Either delete the word
weak
or, if you are intent on maintaining a weak reference to the text field, use a different pattern, such as this:Personally, what I do is not that. I do this:
In real life, that code would be in the
setup
routine. In other words, I make it thesetup
routine's job to make the views and assign them to their weak references while at the same time putting them into the interface.Still another possibility, of course, is just to drop
weak
and do nothing else. MaketextField
a strong reference! There is absolutely nothing wrong with having a strong reference to a subview — unless, of course, that subview also has a strong reference to you, but that is unlikely and can be prevented if it arises.