Search code examples
iosswiftrefactoringnsattributedstringnsmutableattributedstring

Swift: Refactoring NSMutableAttributedString


I have used NSMutableAttributedString/NSAttributedString here and there but don't have extensive experience with them. I have a code block that repeats itself and was wondering how would I go about refactoring it? I've been working on a few extensions to refactor this but haven't had any luck.

The attributes goes into a UILabel variable closure.

let attributes = NSMutableAttributedString(string: "ID: \n",
                                               attributes: [NSAttributedString.Key.foregroundColor : UIColor.black,
                                                            NSAttributedString.Key.backgroundColor : UIColor.clear,
                                                            NSAttributedString.Key.font : UIFont(name: "Helvetica", size: 15)!])
    attributes.append(NSMutableAttributedString(string: "\(nameID)",
                                                attributes: [NSAttributedString.Key.foregroundColor : UIColor.white,
                                                             NSAttributedString.Key.backgroundColor : UIColor.customBlue(),
                                                             NSAttributedString.Key.font : UIFont(name: "Helvetica", size: 15)!]))
    attributes.append(NSMutableAttributedString(string: "\nDate Created: \n",
                                                attributes: [NSAttributedString.Key.foregroundColor : UIColor.black,
                                                             NSAttributedString.Key.backgroundColor : UIColor.clear,
                                                             NSAttributedString.Key.font : UIFont(name: "Helvetica", size: 15)!]))
    attributes.append(NSMutableAttributedString(string: "TEST",
                                                attributes: [NSAttributedString.Key.foregroundColor : UIColor.white,
                                                             NSAttributedString.Key.backgroundColor : UIColor.customBlue(),
                                                             NSAttributedString.Key.font : UIFont(name: "Helvetica", size: 15)!]))
    attributes.append(NSMutableAttributedString(string: "\nDate Last Used: \n",
                                                attributes: [NSAttributedString.Key.foregroundColor : UIColor.black,
                                                             NSAttributedString.Key.backgroundColor : UIColor.clear,
                                                             NSAttributedString.Key.font : UIFont(name: "Helvetica", size: 15)!]))
    attributes.append(NSMutableAttributedString(string: "TEST",
                                                attributes: [NSAttributedString.Key.foregroundColor : UIColor.white,
                                                             NSAttributedString.Key.backgroundColor : UIColor.customBlue(),
                                                             NSAttributedString.Key.font : UIFont(name: "Helvetica", size: 15)!]))

Solution

  • Try looking at your code and seeing if there's a pattern. What I see is creating multiple NSAttributedStrings with String values, setting foreground and background, and the same font over and over. So this is ripe for the refactor picking.

    First, set up your data:

    // one note here is that you actually have a newline char for every entry, so it's probably better practice t simply drop them and apply them in your loop which we'll get to
    let values = ["ID:", nameID /*I assume this is already a `String`*/, "Date Created: ", "TEST", "Date Last Used:", "Test"]
    

    Colors seem to follow their own pattern: titles are black on clear and values are white on custom blue. We can use this in our loop, too. Let's set up our attributes so they're easy to reference:

    let titleAttributes: [NSAttributedString.Key: Any] = [
      .foregroundColor: UIColor.black,
      .backgroundColor: UIColor.clear,
      .font: UIFont(name: "Helvetica", size: 15)!
    ]
    
    let valueAttributes: [NSAttributedString.Key: Any] = [
      .foregroundColor: UIColor.white,
      .backgroundColor: UIColor.customBlue(),
      .font: UIFont(name: "Helvetica", size: 15)!
    ]
    

    Now, let's loop:

    let mutableString = NSMutableAttributedString()
    
    for (index, currentValue) in values.enumerated() {
      // if we're on an even number, we have a title. If it's odd, it's a value
      let attributes = index % 2 == 0 ? titleAttributes : valueAttributes
    
      // if we aren't on the last index, add a newline to the value
      let value = index < values.count - 1 ? "\(currentValue)\n" : currentValue
    
      mutableString.appendAttributedString(string: value, attributes: attributes)
    }