2016-12-24 2 views
3

это мой первый пост! Я относительно не знаком с Swift, и у меня нет опыта в области компьютерных наук, поэтому я все еще склонен к множеству проблем с новичками, но до сих пор я смог решить их все, отчасти от просмотра превосходных ответов на StackOverflow. Тем не менее, я столкнулся с чем-то, что действительно сильно меня озадачило, и я потратил целую неделю, пытаясь решить ее без везения.Swift - итерация через символы в строке вызывает утечку памяти

То, что я пытаюсь сделать, это взять текст на китайском языке из UITextView, а затем преобразовать его в массив отдельных китайских символов, который затем используется для различной обработки и анализа. Однако это вызывает утечку.

В этом очень упрощенном примере, который воспроизводит те же утечки, есть TextView и Button; когда пользователь нажимает кнопку, вызывается функция makeArray, которая преобразует текст в массив символов (на самом деле это строки одиночных символов, потому что мне нужно, чтобы это были строки для некоторых вещей, которые я буду делать с ним). Класс TextProcessing, который содержит эту функцию, используется как одноэлементный (да, я знаю, что, по-видимому, синглтоны должны быть плохими по причинам, которые я не совсем понимаю, но по разным причинам, связанным с другими частями кода, он лучше всего работает, когда это единственный экземпляр этого класса), и текст из UITextView передается в нее, где она затем преобразуется в массив, как вы можете увидеть ниже:

class ViewController: UIViewController { 
    @IBOutlet weak var textBox: UITextView! 
    @IBOutlet weak var doneButton: UIButton! 

    @IBAction func pressDoneButton(_ sender: Any) { 
     let textToAnalyze = textBox.text! 
     TextProcessing.textProcessing.makeArray(textToAnalyze) 
    } 
} 

class TextProcessing { 
    static let textProcessing = TextProcessing() 

    private let language = "Chinese" 
    private var sourceTextArray: [String]! 

    func makeArray (_ sourceText: String) { 
     if language == "Chinese" { 
      sourceTextArray = sourceText.characters.map { String($0) } 
     } else if language == "English" { 
      sourceTextArray = sourceText.components(separatedBy: " ") 
     } 
     // then do some stuff with this array 
    } 
} 

Когда я бегу это на утечках инструменты I получить утечки «Malloc 16 Bytes» и «CFString», причем количество экземпляров каждого из них примерно совпадает с количеством элементов массива (таким образом, количество символов в строке). Когда я смотрю на Дерево вызовов и разворачиваюсь, проблема связана с «sourceTextArray = sourceText.characters.map {String ($ 0)}».

Кстати, это происходит с относительно длинными текстами - с короткими, либо нет проблем, либо Инструменты не обнаруживают его.

Однако, если я создаю массив, разделив строку на слова в соответствии с пробелами, как хотелось бы на таком языке, как английский, утечки нет - поэтому, если я изменю языковую переменную на «английский» в примере кода , он отлично работает (но, конечно, не дает мне массив, который я хочу). Я думал, что, возможно, проблема была в методе «карта», поскольку она использует закрытие, и легко получить утечки с закрытием, но когда я пытаюсь использовать другие способы поместить его в массив символов, например, используя цикл for и итерации по каждому персонажу таким образом, у него все еще есть та же проблема.

Если, вместо того, чтобы текст из UITextView, я делаю это вместо:

class ViewController: UIViewController { 
    @IBOutlet weak var textBox: UITextView! 
    @IBOutlet weak var doneButton: UIButton! 

    @IBAction func pressDoneButton(_ sender: Any) { 
     let textToAnalyze = "blah blah put a long string of Chinese text here" 
     TextProcessing.textProcessing.makeArray(textToAnalyze) 
    } 
} 

нет никаких проблем. Точно так же, если в функции makeArray, если я игнорирую sourceText и вместо того, чтобы сделать это:

func makeArray (_ sourceText: String) { 
    if language == "Chinese" { 
     let anotherText = "blah blah some text here" 
     sourceTextArray = anotherText.characters.map { String($0) } 
    } 
    // then do some stuff with this array 
} 

нет также никакой утечки. Итак, что-то о комбинации получения строки из текстового поля, передачи ее в функцию, а затем вставки ее в массив символов вызывает утечку.

Я провел бесчисленное количество часов, прочесывая интернет и прочитывая все о ARC в Swift, и я пробовал всевозможные вещи со слабым/неработающим и т. Д., И ничего не работает. Что здесь происходит и как это можно решить?

Edit:

Так что кажется, что это может быть просто проблема с Simulator и/или инструменты.Когда я запускаю его на устройстве и просто отслеживаю использование памяти в отладке xcode, нет увеличения даже при выполнении его 100 раз, поэтому я думаю, что все в порядке ... По-прежнему кажется странным, что это может показать утечку в Инструментах.

+0

Он отлично работает. Я пробовал ваш код с очень длинным текстом - около миллиона китайских символов :) - и никакой утечки! – 3li

+0

class TextProcessing {static let textProcessing = TextProcessing()} ... Я не знаю, является ли это проблемой, но вам, разумеется, не нужно переустанавливать этот класс как переменную класса внутри себя. Создание объекта! –

+0

@ 3li Это странно ... он постоянно течет каждый раз, когда я пробую его с чем-то большим, чем несколько парагафов. Я использую XCode 8.2.1 с Swift 3. Что относительно распределения памяти - даже если он не обнаруживает утечку для вас, увеличивается ли общая память, если вы повторно нажимаете кнопку «Готово»? – Jason210006

ответ

1

Это ошибка инструментов (есть много проблем). Ваш код в порядке.

+0

Хмм, я не совсем уверен. Это, конечно, может быть просто ошибкой в ​​инструменте Leaks, когда я запускаю его в Allocations, общая память постоянно увеличивается, когда я несколько раз нажимаю кнопку. Даже когда я не запускаю его в инструментах вообще, и просто в Simulator, когда я многократно нажимаю кнопку, общая память продолжает расти и вверх ... так ясно, что что-то не работает так, как должно. – Jason210006

+0

ОК, поэтому после некоторого тестирования вам кажется, что вы правы. Проблема в том, что я тестировал его только на симуляторе, а не на устройстве. Когда я тестирую его на устройстве, инструмент Leaks по-прежнему показывает те же утечки, и Allocations все еще показывает, что память неуклонно растет, но когда я запускаю его на устройстве и просто смотрю на память в статистике отладки xcode, нет увеличения в памяти, даже когда я делаю это в 100 раз. (в Simulator он показывает, что память растет каждый раз даже в xcode). Итак, я думаю, что эта комбинация (xcode + device) является самой точной, и поэтому она прекрасна ??? странно .. – Jason210006

+0

Да, это странно. Но инструменты - тяжелый инструмент, очень сложно написать его без ошибок. Также Xcode содержит много проблем :) –