Ios 超过最大文本(";)连接长度-SwiftUI-

Ios 超过最大文本(";)连接长度-SwiftUI-,ios,swift,swiftui,Ios,Swift,Swiftui,关于Asperi()发布的关于以下问题的答案: 我发现他的答案非常有用,但是,当我的字符串输入超过32k个字符时,应用程序就会崩溃,所以我假设String()的最大值为32k,我正在寻找解决方法 在我的应用程序中,如果有人搜索“pancake”一词,搜索词将被存储,当用户查看详细信息页面(比如食谱)时,pancake一词将突出显示。所有这些都适用于这个答案,但当配方超过32k个字符时,应用程序会崩溃,并显示超出索引范围的消息。(特定错误消息:线程1:EXC\U BAD\U访问(代码=2,地址=0

关于Asperi()发布的关于以下问题的答案:

我发现他的答案非常有用,但是,当我的字符串输入超过32k个字符时,应用程序就会崩溃,所以我假设String()的最大值为32k,我正在寻找解决方法

在我的应用程序中,如果有人搜索“pancake”一词,搜索词将被存储,当用户查看详细信息页面(比如食谱)时,pancake一词将突出显示。所有这些都适用于这个答案,但当配方超过32k个字符时,应用程序会崩溃,并显示超出索引范围的消息。(特定错误消息:线程1:EXC\U BAD\U访问(代码=2,地址=0x16d43ffb4))

以下是该问题答案中的修改代码:

这将打印数据:

hilightedText(str: self.recipes.last!.recipeData!)
                        .multilineTextAlignment(.leading)
                        .font(.system(size: CGFloat( settings.fontSize )))
上面的代码显然还有更多内容,但本质上,它迭代数据库,找到包含“search word”的最后一条记录,并在此处显示recipeData,这是数据库中包含的一个大字符串

要实现highlightedText功能,请执行以下操作:

    func hilightedText(str: String) -> Text {
        let textToSearch = searched
        var result: Text!
        for word in str.split(separator: " ") {
            var text = Text(word)
            if word.uppercased().contains(textToSearch.uppercased()) {
                text = text.bold().foregroundColor(.yellow)
            }
            //THIS NEXT LINE has been identified as the problem:
            result = (result == nil ? text : result + Text(" ") + text)
        }
        return result
    }
我已经稍微修改了Asperi的答案,以满足我的需要,所有的工作都非常好,除非我遇到一个recipeData条目,如前所述,它的大小大于32k

我尝试过用一些其他数据类型替换
String
,但没有任何效果

有什么想法吗

谢谢大家!

更新:

在评论中经过长时间的讨论后,问题的根本原因似乎是在某个时候,对于某些记录,我超过了最大文本(“”)连接

在上面的代码中,每个单词都被拆分、求值并添加到长字符串“result”中,结果如下所示:
Text(“word”)+Text(“word”)+Text(“word”)
等等

这就完成了,所以我可以很容易地为每个单词应用颜色属性,但似乎一旦我点击了一定数量的单词(少于32k,一条记录是22k并崩溃),应用程序就会崩溃

Leo建议将此线程作为替代方案,我将不得不尝试实现它


谢谢。

在评论中进行了大量讨论之后,很明显我达到了最大Text()连接限制,所以要小心,显然有一个限制

然而,我意识到,我只需要在特定单词需要特殊格式(如突出显示等)时使用拆分文本(“单词”),否则,我可以将所有原始字符串合并在一起,并将其作为文本(“单词字符串”)发送

这种方法减轻了将每个单词单独作为文本(“单词”)发送的行为,并大大减少了返回Text()的数量

请参阅下面解决问题的代码:

func hilightedText(str: String) -> Text {
    let textToSearch = searched
    var result = Text(" ")
    var words: String = " "
    var foundWord = false
    for line in str.split(whereSeparator: \.isNewline) {
        for word in line.split(whereSeparator: \.isWhitespace) {
            if word.localizedStandardContains(textToSearch) {
                foundWord = true
                result += Text(words) + Text(" ") + Text(word).bold().foregroundColor(.yellow)

            } else {
                if foundWord {
                    words = ""
                }
                foundWord = false
                words += " " + word
            } 
        }
        words += "\n\n"
    }
    return result + Text(" ") + Text(words)
}

它可以使用一些清理,正如在注释中讨论的那样,通过空格等进行拆分,但这只是为了克服崩溃问题。在我称之为良好之前,需要进行一些额外的测试,但不再崩溃

增加:
使用separator by.isWhiteSpace的建议奏效了,但当我把它放回一起时,一切都是一个空格,没有更多的换行符,所以我添加了额外的按换行符分割以保留换行符。

嗯…意外的限制…无论如何-学习一些新东西

好的,这是一个改进的算法,它应该可以将这个限制移到很远的地方

使用Xcode 12/iOS 14进行测试。(也更新了参考主题中的代码)

func-hilightedText(str:String,searched:String)->Text{
guard!str.isEmpty&!searched.isEmpty else{返回文本(str)}
变量结果=文本(“”)

var range=str.startIndex..与您的问题无关,但您可以简单地使用
localizedStandardContains
(区分重音和大小写)
word.localizedStandardContains(textToSearch)
Thx Leo,如果我希望它能处理更长的字符串,我会清理它。顺便说一句,str.split中的单词使用
(whereSeparator:\.isWhitespace)
whereSeparator:\.isWhitespace似乎删除了所有换行符(\n)…我开始怀疑字符串长度超过32k不是我的问题。做一些进一步的调试,当我弄明白它时,会改变问题。.评论不是为了进一步讨论;这段对话一直是。还谢谢Asperi,这个答案还解决了其他答案没有解决的一些意外后果,例如preserving如果单词对同时出现,则显示原始空格并突出显示多个搜索词。-接受答案。Thx!您可以使用
localizedStandardRange
进行区分重音和大小写的搜索。
guard let found=str[range]。localizedStandardRange(of:searched)
var range=str.startIndex…
重复{
guard let found=str[range]。本地化标准范围(of:search)其他{
结果=结果+文本(str[range])
中断
结果+文本(str[range.lowerBound..or
var range=str.startIndex…
而let found=str[range].localizedStandardRange(of:searched){
result=result+Text(str[range.lowerBound
extension Text {
    static func += (lhs: inout Text, rhs: Text) {
        lhs = lhs + rhs
    }
}
func hilightedText(str: String, searched: String) -> Text {
    guard !str.isEmpty && !searched.isEmpty else { return Text(str) }

    var result = Text("")

    var range = str.startIndex..<str.endIndex
    repeat {
        guard let found = str.range(of: searched, options: .caseInsensitive, range: range, locale: nil) else {
            result = result + Text(str[range])
            break
        }

        let prefix = str[range.lowerBound..<found.lowerBound]
        result = result + Text(prefix) + Text(str[found]).bold().foregroundColor(.yellow)

        range = found.upperBound..<str.endIndex
    } while (true)

    return result
}