Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
1.0k views
in Technique[技术] by (71.8m points)

ios - Exceeding max Text("") concatenation length - SwiftUI -

With reference to the answer posted by Asperi (https://stackoverflow.com/users/12299030/asperi) on Question: Highlight a specific part of the text in SwiftUI

I have found his answer quite useful, however, when my String input exceeds 32k characters the app crashes, so I am assuming the String() is a max of 32k and am looking for a work around.

In my app, if someone searches for the word "pancake", the search word will be stored and when the user looks at the detail page (of lets say a recipe), the word pancake will highlight. All works well with this answer, but when the recipe exceeds 32k characters, the app crashes with exceeding index range messages. (specific error message: Thread 1: EXC_BAD_ACCESS (code=2, address=0x16d43ffb4))

Here is the modified code from the answer on that question:

This will print the data:

hilightedText(str: self.recipes.last!.recipeData!)
                        .multilineTextAlignment(.leading)
                        .font(.system(size: CGFloat( settings.fontSize )))

There is obviously more to this code above, but in essence, it iterates a database, and finds the last record containing 'search word' and displays the recipeData here, which is a large string contained in the database.

to implement the highlightedText functionality:

    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
    }

I've modified the answer from Asperi slightly to suit my needs and all works really well, unless I come across a recipeData entry that is larger than 32k in size, as stated before.

I have tried Replacing String with a few other data types and nothing works..

Any ideas?

Thank you!

UPDATE:

After lengthy discussion in the comments, it appears that the root cause of the issue is at some point, for some records, I am exceeding the maximum Text("") concatenations.

In the above code, each word is split out, evaluated and added to the long string "result" which winds up looking like this: Text("word") + Text(" ") + Text("Word") and so on.

This is done, so I can easily apply color attributes per word, but it would seem that once I hit a certain number of words (which is less that 32k, one record was 22k and crashed), the app crashes.

Leo suggested https://stackoverflow.com/a/59531265/2303865 this thread as an alternative and I will have to attempt to implement that instead.

Thank you..

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Hmm... unexpected limitation... anyway - learn something new.

Ok, here is improved algorithm, which should move that limitation far away.

Tested with Xcode 12 / iOS 14. (also updated code in referenced topic Highlight a specific part of the text in SwiftUI)

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
}

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...