2017-01-31 2 views
8

Я нашел, что время окраски строк зависит от количества различных NSColors. В приведенном ниже коде, если я использую только один цвет для трех случаев, процесс окрашивания текста в 3 раза быстрее, чем в случае, когда для этих трех случаев используются три разных цвета, каждый цвет для каждого случая. Зачем ? Есть ли способ не замедлить окраску для трех разных цветов?Как использовать цвет для раскраски текста без замедления процесса?

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 я нашел еще одну вещь BAD. Когда я изменил окраску от NSForegroundColorAttributeName до NSBackgroundColorAttributeName, время работы значительно увеличилось - в 10 раз. Для 20 000 символов это было для одного цвета, для NSForegroundColorAttributeName - 1 сек., Для NSBackgroundColorAttributeName - 10 сек; если три цвета - 3 и 30 секунд соответственно. Для меня это очень плохая особенность Swift !!! Невозможно выполнить нормальную работу с окраской ДНК (ATGC), поскольку длина ДНК составляет тысячи символов A, T, G, C!

Обновление В комментариях у меня есть предложение по цвету только видимой части текста. Я пробовал этот подход, и это намного хуже даже для более короткого текста по сравнению с тем, что я делал стандартным образом. Таким образом, у меня был NSRange текста для видимой части текста и выполнялся раскраска на лету, прокручивая с помощью уведомления при прокрутке. Это плохо.

+0

В зависимости от конкретных диапазонов, к которым применяется цвет, они могут объединяться в один проход всех одинаковых атрибутов. Или, по крайней мере, меньше пробегов, чем при использовании цветов разницы. Для каждой операции есть отдельная операция рисования с накладными расходами для каждой операции. Вы можете использовать 'enumerateAttributes (in: options: using:)', чтобы узнать, сколько прогонов существует для каждого случая. –

+0

@Ken Thomases Я проверил строку около 180 000 символов, состоящую из символов A, G, T и C в разных количествах, на самом деле это последовательность ДНК. Сначала я определяю диапазоны для каждого A, G, T и C. Итак, у меня есть 4 массива диапазонов, а затем I цветные символы A, G, T и C. – VYT

+0

@ Ken Thomases, поскольку массивы для каждого C, G, A и T одинаковы для одного цвета или для трех цветов, объединение уровней может происходить только во время процесса окрашивания, а затем это означает, что некоторая окраска для каждого цикла зависит от других циклов ?? – VYT

ответ

2

Самое большое препятствие выложив все эти приписываемые символы в текстовом виде. Раскрасить последовательность ДНК занимает минимальное время. Вместо того чтобы писать свой собственный класс менеджера компоновки или текст для хранения, вы можете принять разделяй и властвуй подход, раскрашивание вид текста на куски в то время:

@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 
} 

Хитрость заключается в том, чтобы сделать приложение, как реагировать, как возможно, поэтому пользователь не знает, что все еще делается в фоновом режиме. С небольшим delay (< = 0,3 секунды) я не мог прокрутить мою мышь достаточно быстро, чтобы дойти до конца текстового вида, прежде чем все было раскрашено (100 тыс. Символов).

На 100-значный тест потребовалось 0,7 секунды, пока цветная строка сначала не появилась внутри текстового представления вместо 7 секунд, если бы я сделал все сразу.

+0

Спасибо за ответ! Нет, я поставил 'setAttributedString' как в вашем коде. Только отличия - это первый вывод NSRanges для каждого A, T, C, а затем раскраска, а не использование 'switch'. Я выполняю выравнивание двух строк, а затем раскрашивание комбинированной строки. Итак, я написал немного неправильно о длине строки. Я использовал около 20 000 для каждого, поэтому объединенная строка составляет около 40 000, а это около 3 секунд. Для вашего кода (я проверил) результаты схожи. Я проголосовал за ваш ответ, потому что это другой способ раскрасить цепочку ДНК. К сожалению, это не решение проблемы. – VYT

+0

При более глубоком просмотре создание атрибутной строки было очень быстрым (<1 с для 100-символьной строки). Это заставляет их «NSTextView» медленно. Я возьму более глубокое погружение в «NSTextView» и обновляю свой ответ после работы. –

+0

Еще раз спасибо! Я принимаю ваш ответ как решение и адаптирую свой код для своего приложения. – VYT

-1

Вы пытались использовать ciColor вместо атрибута? ciColors может использоваться с текстом, изображениями и фоном.

Вы можете попробовать так:

txtField.textColor?.ciColor.red 
+0

Я не могу найти, как использовать ciColor в NSTextView. У меня есть красный цвет - «Вы используете объекты CIColor в сочетании с другими классами Core Image, такими как CIFilter, CIContext и CIImage» – VYT

Смежные вопросы