错误 "NSMutableRLEArray objectAtIndex:effectiveRange:: Out of bounds'"

Error "NSMutableRLEArray objectAtIndex:effectiveRange:: Out of bounds'"

我有以下代码,其中我传递了一个类型为 "Hello|r World|g" 的字符串,下面的函数将其转换为 attributedString"Hello"red颜色和 "World"green 颜色。我在传递数组中的每个字符串时使用了它。该函数只为文本着色,直到它找到一个特殊字符,如结束期间的条件所示,然后为文本着色。

代码:

func formatAttributedString(string:String)->NSMutableAttributedString {
        var strCopy=string as NSString
        var color:UIColor=UIColor()
        var attributedString:NSMutableAttributedString!

        for var i:Int=0;i<strCopy.length-2;i++ {
            if (string[i] == "|") {
                println("|")
                var j:Int
                if string[i+1] == "r" {
                    color=UIColor(red: 249, green: 39, blue: 14, alpha: 1)
                    strCopy = strCopy.stringByReplacingOccurrencesOfString("|r", withString: "", options: NSStringCompareOptions.LiteralSearch, range: NSMakeRange(0, i + 2))
                    println("r")

                }
               else  if string[i+1] == "v" {
                    color=UIColor(red: 161, green: 153, blue: 249, alpha: 1)
                    strCopy = strCopy.stringByReplacingOccurrencesOfString("|v", withString: "", options: NSStringCompareOptions.LiteralSearch, range: NSMakeRange(0, i + 2))
                    println("v")

                }
                else if string[i+1] == "y" {
                    color=UIColor(red: 235, green: 223, blue: 145, alpha: 1)
                    strCopy = strCopy.stringByReplacingOccurrencesOfString("|y", withString: "", options: NSStringCompareOptions.LiteralSearch, range: NSMakeRange(0, i + 2))
                    println("y")
                }
                else if string[i+1] == "g" {
                    color=UIColor(red: 174, green: 227, blue: 79, alpha: 1)
                    strCopy = strCopy.stringByReplacingOccurrencesOfString("|y", withString: "", options: NSStringCompareOptions.LiteralSearch, range: NSMakeRange(0, i + 2))
                    println("g")
                }
                else if string[i+1] == "b" {
                    color=UIColor(red: 107, green: 224, blue: 240, alpha: 1)
                    strCopy = strCopy.stringByReplacingOccurrencesOfString("|b", withString: "", options: NSStringCompareOptions.LiteralSearch, range: NSMakeRange(0, i + 2))
                    println("b")
                }


                for j=i; j>=0;j-- {
                    if string[j] == " " || string[j] == "/" || string[j] == "." || string[j] == "\"" || string[j] == "\n" || string[j] == "<" || string[j] == "\t" || string[j] == "("{
                        println("/")
                        break

                    }
                }
                attributedString=NSMutableAttributedString(string: strCopy)
                attributedString.addAttribute("NSForegroundColorAttributeName", value: color, range: NSMakeRange(j, i-j))

            }
        }

我收到以下错误:

'NSMutableRLEArray objectAtIndex:effectiveRange:: Out of bounds'

正如我添加的 printlns , |r 得到打印。 请帮助,提前致谢。

这不是 this question 的副本,因为正在打印 |r

我猜错误发生在这一行:

attributedString.addAttribute("NSForegroundColorAttributeName", value: color, range: NSMakeRange(j, i-j))

让我们看看您的字符串 "Hello|r World|g" - 它有 15 个字符长。 让我们看看外部 for 找到第二个“|”时的迭代。 strCopy 现在是 "Hello World|g" - 13 个字符长,i = 11。 程序找到一个“|”然后是 "r" 并将 strCopy 更改为 "Hello World|g" - 11 个字符长,但 i = 11.

在内部 for 中的 "scan" 之后,我们最终得到 j = 7。

在这一行中,您从 "Hello World":

创建了一个可变字符串

attributedString=NSMutableAttributedString(string: strCopy)

它与 strCopy 本身一样,长度等于 11。

现在,在最后一行中,您为 NSRangeMake(7, 4) 范围内的字符设置属性,这意味着它应用的最后一个字符将在索引 11 处。此字符串中的最后一个索引是 10,即为什么会崩溃。

编辑: 为避免此崩溃,您应该在每行 stringByReplacingOccurencesOfString.

之后添加 "i--;"

你还应该做的另一件事(不会导致崩溃,但仍然会导致故障)是更改内部 for 以便循环行如下所示:

for j = i + (string.length - strCopy.length); j>=0; j-- {

您的算法似乎依赖于 i 指向最后处理的字符。每当你遇到 |?模式,您最终用“”替换了两个特殊字符,有效地将复制字符串大小减少了 2.

解决问题的最简单方法是在每次调用 strCopy.stringByReplacingOccurrencesOfString... 后添加 i=i-2

这使 i 函数末尾的代码保持正确。

理想情况下,您可能需要考虑重组功能以将项目从原始版本移动到新版本,同时添加颜色等。这将节省所有向后搜索。

我已经尝试使用 Swift 的匿名元组和更高阶函数的另一个实现来满足您的函数签名。我这样做是为了自己练习,最后认为最好分享一下。

func formatAttributedString(string: String) -> NSMutableAttributedString {
    // create a mapping between the attribute token and the corresponding UIColor
    let colors = [
        "|r": UIColor(red: 249/255, green:  39/255, blue:  14/255, alpha: 1.0),
        "|v": UIColor(red: 161/255, green: 153/255, blue: 249/255, alpha: 1.0),
        "|y": UIColor(red: 235/255, green: 223/255, blue: 145/255, alpha: 1.0),
        "|g": UIColor(red: 174/255, green: 227/255, blue:  79/255, alpha: 1.0),
        "|b": UIColor(red: 107/255, green: 224/255, blue: 240/255, alpha: 1.0)]

    // split argument into an array of (String, UIColor) tuples

    // default the array to the entire argument string with a black color
    var substrings = [(string, UIColor.blackColor())]

    for (token, color) in colors {
        substrings = substrings.flatMap {
            var substrings = [=10=].0.componentsSeparatedByString(token)
            let tail = (substrings.removeLast(), [=10=].1)   // tuple for trailing string at old color
            var result = substrings.map{([=10=], color)}     // array of tuples for strings at new color
            result.append(tail)
            return result
        }
    }
    // because we default the original string to black, there may be an empty string tuple at the end
    substrings = substrings.filter{(string, _) in return !string.isEmpty}

    // convert array of (String, UIColor) tuples into a single attributed string
    var result = reduce(substrings, NSMutableAttributedString(string: "")) {
        var string = NSAttributedString(string: .0, attributes: [NSForegroundColorAttributeName: .1])
        [=10=].appendAttributedString(string)
        return [=10=]
    }
    return result
}