swiftstring

Cannot convert value of type 'Int' to expected argument type 'AttributedString.Index'


Sorry I am still a bit new to swift. I have searched on here but all I could find are outdated answers. How do I construct the AttributedString.Index for insert(_ s: some AttributedStringProtocol, at index: AttributedString.Index).

I know I can just add them together but this is just a small piece of what I am actually working on.

    func setFooterMessage() -> AttributedString {
        var mOne = AttributedString("Play   Monday")
        mOne.foregroundColor = .white
        
        let mTwo = AttributedString("on")
        mOne.insert(mTwo, at: 6) // error
        
        return mOne
    }

Solution

  • I'm not entirely sure where the 6 comes from or why there are 3 spaces in "Play Monday", as they cause a rather oddly asymmetric output, but the initialisers you need are as follows:

    func setFooterMessage() -> AttributedString {
        var s: String = "Play   Monday"
        var mOne = AttributedString(s)
        mOne.foregroundColor = .white
            
        let mTwo = AttributedString("on")
        // *** You need to get the base index from the `String`
        let i = String.Index(utf16Offset: 6, in: s)
        // *** and from that you can get the index into the `AttributedString`
        if let ia = AttributedString.Index(i, within: mOne) {
            // ... but it's optional, as obviously it could fail
            mOne.insert(mTwo, at: ia) // no error now
        }
        return mOne
    }
    

    The rationale behind String.Index as opposed to Int has been explained in hundreds of answers here and elsewhere, but the overly simplified answer is that in Swift Strings are Unicode sequences, not byte arrays.

    AttributedStrings are even more complex in that they have embedded attributes (colours, fonts or even entire images) and so to refer in any meaningful sense to a position in the AttributedString's character sequence, you must do so with reference to the equivalent String.