How to use color to color text without slowing down the process?

I found that the staining time of strings depends on the number of different NSColors. In the code below, if I use only one color for three cases, the process of coloring the text is 3 times faster than when three different colors are used for these three cases, each color for each case. What for? Is there a way to not slow down the coloring for three different colors?

for i in 0..<arrayOfNSRangesForA.count { textFromStorage.addAttribute(NSForegroundColorAttributeName, value: NSColor.green, range: arrayOfNSRangesForA[i]) } for i in 0..<arrayOfNSRangesForT.count { textFromStorage.addAttribute(NSForegroundColorAttributeName, value: NSColor.green, range: arrayOfNSRangesForT[i]) } for i in 0..<arrayOfNSRangesForC.count { textFromStorage.addAttribute(NSForegroundColorAttributeName, value: NSColor.green, range: arrayOfNSRangesForC[i]) } 

Update I found another OTHER thing. When I changed the color from NSForegroundColorAttributeName to NSBackgroundColorAttributeName , the runtime increased significantly - 10 times. For 20,000 characters, this was for one color, for NSForegroundColorAttributeName - 1 second, for NSBackgroundColorAttributeName - 10 seconds; if three colors - 3 and 30 seconds respectively. For me, this is a very bad feature of Swift !!! Normal DNA staining (ATGC) is not possible because the DNA is thousands of characters A, T, G, C!

Update In the comments, I have a suggestion to color only the visible part of the text. I tried this approach, and it is much worse even for shorter text compared to what I did in a standard way. Thus, I had NSRange of text for the visible part of the text, and the coloring was done on the fly, scrolling through the notification when scrolling. This is bad.

+8
arrays swift nsattributedstring nscolor
source share
2 answers

The biggest hurdle is highlighting all of these attributes in a text view. Coloring the DNA sequence takes minimal time. Instead of writing your own layout manager or text repository, you can use the divide and conquer approach by coloring the text representation in pieces at a time:

 @IBOutlet var textView: NSTextView! var dnaSequence: String! var attributedDNASequence: NSAttributedString! @IBAction func colorize(_ sender: Any) { self.dnaSequence = "ACGT" // your plaintext DNA sequence self.attributedDNASequence = self.makeAttributedDNASequence() // Rendering long string with the same attributes throughout is extremely fast self.textView.textStorage?.setAttributedString(NSAttributedString(string: dnaSequence)) let step = 10_000 // colorize 10k characters at a time let delay = 0.2 // delay between each render for (i, location) in stride(from: 0, to: self.dnaSequence.characters.count, by: step).enumerated() { let length = min(step, self.dnaSequence.characters.count - location) let range = NSMakeRange(location, length) // Since we are modifying the textStorage of a GUI object (NSTextView) // we should do it on the main thread DispatchQueue.main.asyncAfter(deadline: .now() + (delay * Double(i))) { let subtext = self.attributedDNASequence.attributedSubstring(from: range) print("Replacing text in range \(location) to \(location + length)") self.textView.textStorage?.replaceCharacters(in: range, with: subtext) } } } // MARK: - var colorA = NSColor.red var colorC = NSColor.green var colorG = NSColor.blue var colorT = NSColor.black func makeAttributedDNASequence() -> NSAttributedString { let attributedText = NSMutableAttributedString(string: dnaSequence) var index = dnaSequence.startIndex var color: NSColor! for i in 0..<dnaSequence.characters.count { switch dnaSequence[index] { case "A": color = colorA case "C": color = colorC case "G": color = colorG case "T": color = colorT default: color = NSColor.black } attributedText.addAttribute(NSForegroundColorAttributeName, value: color, range: NSMakeRange(i,1)) index = dnaSequence.index(after: index) } return attributedText } 

The trick is to make the application as flexible as possible so that the user does not know what is still being done in the background. With a slight delay (<= 0.3 seconds), I could not scroll my mouse fast enough to reach the end of the text view before everything was colorized (100 thousand characters).

It took 0.7 seconds for the 100-digit test, until the color line first appeared inside the text view, and not 7 seconds if I did everything at once.

+2
source share

Have you tried using ciColor instead of an attribute? ciColors can be used with text, images and backgrounds.

You can try the following:

 txtField.textColor?.ciColor.red 
-one
source share

All Articles