起きたこと
UILabel の attributedText
を nil (リセット) にしてもラベルのスタイルが変わらないという現象が発生していました。
TL;DR
原因
UILabel の attributedText の値が nil(リセット)になった場合、通常(iOS12以前)は Label の attributes もリセットされるが iOS13 ではリセットされないとの報告があり、それが起因して考えられます。
解決策
UILabel の text
・attributedText
はどちらか一方の値が変わるともう一方の値も変わるという連動性があることから(下記ドキュメント)、今回のように text
・attributedText
を共存させて更新することはシステムのバグに限らず望ましくないので、attributedText
のみ明示的に更新処理を行うように修正したところ解決しました。
-
[https://developer.apple.com/documentation/uikit/uilabel/1620542-attributedtext:title]
-
[https://developer.apple.com/documentation/uikit/uilabel/1620538-text:title]
※ iOS13のバグかどうかについては現在のところ不明
具体的な発生タイミングと改善
Before
チャットに表示する UI で、コメントがリンクの場合は青く表示させて Clickable にさせるように UILabel を継承したサブラクス(以降: LinkLabel)を作成していました。基本的な仕様としては LinkLabel の text
プロパティに didSet をセットし、更新されたタイミングでテキストをトリミングして attributedText
を更新するという感じです。
final class LinkLabel: UILabel {
override var text: String? {
didSet {
updateAttributedText()
}
}
func updateAttributedText() {
guard let text = text else {
return
}
let mutableAttributedString = NSMutableAttributedString(string: text)
// 省略....
// いろいろ Attributes をセットする
attributedText = mutableAttributedString
}
}
上記で作成した LinkLabel を Cell に配置して TableView で表示した時に、Cell が再利用されるタイミングで以前の attributes がキャッシュされていて関係ないコメントも青く表示されることがたびたび起こるようになりました。
After
TL;DR
にも記載してある通り、attributedText
だけを明示的に更新することで改善できたので下記のように修正します。
final class LinkLabel: UILabel {
var displayText: String?
func setText(_ text: String?) {
displayText = text
updateAttributedText()
}
func updateAttributedText() {
guard let text = displayText else {
return
}
let mutableAttributedString = NSMutableAttributedString(string: text)
// 省略....
// いろいろ Attributes をセットする
attributedText = mutableAttributedString
}
}
使用する Cell 側でもキャッシュをリセットできるように prepareForReuse()
セットします
final class CommentCell: UITableViewCell {
let linkLabel = LinkLabel()
override func prepareForReuse() {
super.prepareForReuse()
linkLabel.attributedText = nil
}
// 省略...
}
調べたこと
-
UILabel の attributes がリセットされないという事例・報告がありました。
-
解決のヒントは下記にありました。
-
typingAttributes
で attributes が保存されてるからか?と思いましたが、そもそも UITextView のプロパティで UILabel には存在しませんでした。 -
公式ドキュメント