Historically, building rich text in Cocoa has been a tedious task, using NSAttributeString in the Foundation framework, with all the inconsistencies of distinguishing mutable from immutable, passing in a parameter dictionary that requires documentation, and no type checking. The new string interpolation feature in Swift 5 makes it possible to handle custom string literals.

Swift 5 string interpolation

In simple terms, this feature allows developers to implement their own analytic and logical implementations of interpolation in literals. Such as:

let string:CustomString = "\(num: 10)"
Copy the code

This string literal can be handled by implementing a method like func appendInterpolation(num: Int). To achieve this effect, it can be roughly divided into the following steps:

  1. Custom type and followExpressibleByStringInterpolation
  2. Nested compliance in typeStringInterpolationProtocolInterpolation type of
  3. Interpolation types are customized for one to multiple different parametersfunc appenInterpolation(...)Override the method and handle the logic of the corresponding arguments

In this way, string interpolation can theoretically do anything from constructing SQL operations from strings, to regex operations, to generating HTML web pages, and even to some runtime hacks.

Implement AttributeString handling

First custom types, and to realize ExpressibleByStringLiteral support string literals (ExpressibleByStringLiteral ExpressibleByStringLiteral as part of the agreement). So we can build an NSAttributedString with no attributes from string literals.

public struct EasyText {
    public let attributedString: NSAttributedString
}

extension EasyText: ExpressibleByStringLiteral {
    public init(stringLiteral: String) {
        attributedString = NSAttributedString(string: stringLiteral)
    }
}
Copy the code

Then realize ExpressibleByStringInterpolation agreement, nested interpolation type, and follow StringInterpolationProtocol. After the interpolation is built, init(stringInterpolation: stringInterpolation) is used to build a custom type. The appendLiteral method is used for interpolation of normal string types.

extension EasyText: ExpressibleByStringInterpolation {
    public init(stringInterpolation: StringInterpolation) {
        attributedString = NSAttributedString(attributedString: stringInterpolation.rawAttributedString)
    }
    
    public struct StringInterpolation:StringInterpolationProtocol {
        let rawAttributedString:NSMutableAttributedString
        
        public init(literalCapacity: Int, interpolationCount: Int) {
            rawAttributedString = NSMutableAttributedString()}public func appendLiteral(_ literal:String) {
            rawAttributedString.append(NSAttributedString(string: literal))
        }
      
    }
}

Copy the code

Next implement one to multiple appendInterpolation methods, such as adding NSTextAttachment to interpolation support:

public struct StringInterpolation:StringInterpolationProtocol {
  	// ...
		public func appendInterpolation(attachment:NSTextAttachment) {
    		rawAttributedString.append(NSAttributedString(attachment: attachment))
    }
}
Copy the code

EasyText use

The author supports all attributes in NSAttributedString using string interpolation, and implements a library of several hundred lines. Using this library, you can build NSAttributedString in a simple way:

let text:EasyText = "\("font is 30 pt and color is yellow", .font(.systemFont(ofSize: 20)), .color(.blue))"

textView.attributedText = text.attributedString
Copy the code

It has the following features:

  • Type safe, all supportedNSAttributedString.KeyAll have type check
  • Supports multiple platforms, iOS/macOS
  • Support most commonNSAttributedString.Key, there is currently no supported interface to build
  • Support common operators, such as++ =, as well as with other typesString,NSAttributedStringThe operation
  • Support for inserting images

See the examples for more details.

The last

EasyText is open source and can be integrated through Cocoapods, Cathrage, SwiftPackageManager.

If you think it is helpful, please give a star to encourage you. If you have any questions, please feel free to comment.

Refer to the link

StringInterpolation in Swift 5 — Introduction

StringInterpolation in Swift 5 — AttributedStrings

Fix ExpressibleByStringInterpolation