错误“NSMutableRLEArray objectAtIndex:effectiveRange :: Out of bounds”

时间:2015-04-14 10:49:57

标签: ios swift nsmutablearray nsattributedstring nsmutableattributedstring

我有以下代码,其中我传递了一个类型为"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'

当我添加println时,|r会被打印出来。 请帮助,提前致谢。

由于|并且r正在打印,因此this question不重复。

3 个答案:

答案 0 :(得分:1)

我的猜测是错误发生在这一行:

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

让我们看一下你的字符串“Hello | r World | g” - 它的长度为15个字符。 让我们看看外部的迭代,当它找到第二个“|”时。 strCopy现在是“Hello World | g” - 长度为13个字符,i = 11。 程序找到“|”接着是“r”并将strCopy更改为“Hello World | g” - 长度为11个字符且仍为i = 11.

在内部的“扫描”之后,我们以j = 7结束。

在这一行中,您可以从“Hello World”创建一个可变字符串:

attributedString=NSMutableAttributedString(string: strCopy)

就像strCopy本身一样,长度等于11。

现在,在最后一行中,为NSRangeMake(7,4)中的字符设置属性,这意味着它应用的最后一个字符将是索引11.此字符串中的最后一个索引是10,这就是为什么你得到了崩溃。

编辑: 为了避免这种崩溃你应该添加“i--;”在每行之后使用stringByReplacingOccurencesOfString。

你还应该做的另一件事(它不会导致崩溃,但仍会使其失灵,是改变内部,以便循环线看起来像这样:

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

答案 1 :(得分:1)

我尝试使用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 = $0.0.componentsSeparatedByString(token)
            let tail = (substrings.removeLast(), $0.1)   // tuple for trailing string at old color
            var result = substrings.map{($0, 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: $1.0, attributes: [NSForegroundColorAttributeName: $1.1])
        $0.appendAttributedString(string)
        return $0
    }
    return result
}

答案 2 :(得分:0)

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

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

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

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