Why does changing the text of a UILabel not reset text attributes on iOS 13?

Viewed 311

On iOS 12, if one changes the text of a UILabel it resets the text attributes. On iOS 13 however, text attributes such as color, typeface, letter spacing, et cetera are kept when the text is changed. What has changed?

An example:

label.text = "Hello world"
let attributedString = NSMutableAttributedString(string: label.text ?? " ")
attributedString.addAttributes([.foregroundColor: UIColor.red], range: NSRange(location: 0, length: attributedString.length))
label.attributedText = attributedString        
label.text = "What's up world" // Text is red on iOS 13, default black on iOS 12.
2 Answers

Seems like from iOS 13, if you set and attribute to the entire text, it will persist! If you don't apply the attribute on the entire range of the text, it behaves like before.

You have some options to get around it:

  1. Not applying it on the entire range (Happens most of the times):
attributedString.addAttributes([
    .foregroundColor: UIColor.red,
    .backgroundColor: UIColor.green
], range: NSRange(location: 0, length: 3))
  1. Perform a version check (Maybe with a little extension)
@available(iOS 13.0, *)
extension UILabel {
    func setTextWithoutAttributes(_ text: String) {
        // Get rid of the holding attributes instance as Asperi mentioned or in another way you like
        self.attributedText = nil
        // Set the text
        self.text = text
    }
}

You did not reset attributedText, but documentation says - if set, the label ignores the properties above (see below for UILabel.h interface, in obj-c it is more correctly visible):

@property(null_resettable, nonatomic,strong) UIColor     *textColor UI_APPEARANCE_SELECTOR; // default is labelColor
...

// the underlying attributed string drawn by the label, if set, the label ignores the properties above.
@property(nullable, nonatomic,copy)   NSAttributedString *attributedText API_AVAILABLE(ios(6.0));  // default is nil

so behaves as specified (before it might be a bug, that now is fixed)

The solution of your case should be

label.attributedText = attributedString        
...
label.attributedText = nil      // << reset to default !!
label.text = "What's up world"
Related