Извините, я все еще новичок в Swift. Я искал здесь, но все, что я смог найти, это устаревшие ответы. Как мне создать AttributedString.Index для insert(_ s: some AttributedStringProtocol, at index: AttributedString.Index)
.
Я знаю, что могу просто сложить их вместе, но это лишь небольшая часть того, над чем я на самом деле работаю.
func setFooterMessage() -> AttributedString {
var mOne = AttributedString("Play Monday")
mOne.foregroundColor = .white
let mTwo = AttributedString("on")
mOne.insert(mTwo, at: 6) // error
return mOne
}
String
и AttributedString
не работают с индексами Int
, поскольку символы могут иметь более одного байта.
В случае AttributedString
вы можете использовать API index(_:offsetByCharacters:), который вычисляет правильный индекс.
func setFooterMessage() -> AttributedString {
var mOne = AttributedString("Play Monday")
mOne.foregroundColor = .white
let mTwo = AttributedString("on")
let index = mOne.index(mOne.startIndex, offsetByCharacters: 6) // actually 5
mOne.insert(mTwo, at: index)
return mOne
}
Другой способ — получить индекс по диапазону «Play» и вставить подстроку в его upperbound
func setFooterMessage() -> AttributedString {
var mOne = AttributedString("Play Monday")
mOne.foregroundColor = .white
let mTwo = AttributedString("on")
let index = mOne.range(of: "Play ")!
mOne.insert(mTwo, at: index.upperBound)
return mOne
}
Связанный: Как удалить подстроку из строки определенного индекса до некоторой длины в Swift
Я не совсем уверен, откуда взялся 6
и почему в "Play Monday"
3 пробела, поскольку они вызывают довольно странный асимметричный вывод, но вам нужны следующие инициализаторы:
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
}
Обоснование использования String.Index
в отличие от Int
было объяснено в сотнях ответов здесь и в других местах, но слишком упрощенный ответ заключается в том, что в Swift String
— это последовательности Unicode, а не массивы байтов.
AttributedString
еще более сложны, поскольку в них есть встроенные атрибуты (цвета, шрифты или даже целые изображения), и поэтому, чтобы ссылаться в каком-либо значимом смысле на позицию в последовательности символов AttributedString
, вы должны делать это со ссылкой на эквивалент String
.