環境
Swift4.2.1
本題
例えば、以下のようなコードを書いて、xibやstoryboardで設定したattributesを取り出そうとします。
extension NSAttributedString {
var allAttributes: [NSAttributedString.Key: Any] {
return self.attributes(at: 0, effectiveRange: nil)
}
}
すると、文字列が空(isEmpty == true
)の場合にNSRangeException
で落ちます。
😱
attributes(at:effectiveRange:)
のDiscussionに記載がある通りです。
Raises an rangeException if index lies beyond the end of the receiver’s characters.
For a list of possible attributes, see Character Attributes.
文字列がからの場合は、at: 0
が存在しないのでCrashするわけですね。
結果無理
回避策
空文字列でNSAttributedStringを生成しないようにする
以下のようにUILabelのExtensionでisEmptyにならないように、空の場合は半角スペースを入れるようにする。
これなら上で作ったExtensionがバグることもない。
extension UILabel {
func updateAttributedText(_ text: String) {
// スペースいれておかないと、allAttributesが空文字で設定したAttributesを返さなくなる
let string = text.isEmpty ? " " : text
self.attributedText = NSAttributedString(string: string, attributes: self.attributedText?.allAttributes)
}
}
そもそもxibやstoryboardでattributedを設定しない
そもそもxibやstoryboardでattributedを設定しなければ、self.attributedText?.allAttributes
を使わずに、以下のように毎回attributes
を生成して設定すれば良い
extension UILabel {
func setAttributes() {
// lineSpace設定
let pStyle = NSMutableParagraphStyle()
pStyle.lineSpacing = 3
let attr = [NSAttributedString.Key.paragraphStyle: paragraphStyle]
// 文字色設定
attr[NSAttributedString.Key.foregroundColor] = .red
self.attributedText = NSAttributedString(string: self.text, attributes: attr)
}
}
あきらめる
最悪CrashしないようにisEmpty
だけはチェックしとく
extension NSAttributedString {
var allAttributes: [NSAttributedString.Key: Any] {
if self.string.isEmpty {
return [:]
}
return self.attributes(at: 0, effectiveRange: nil)
}
}
最後に
最近IB系の調子が悪いので、使わないほうがいいんじゃあないかなーと思ってきました。
Attribute周りはコードでやったほうが良いのかもしれません。