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
}
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 String
s are Unicode sequences, not byte arrays.
AttributedString
s 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
.