JSONSerialization.jsonObject вызывает утечку памяти в swift 4.0 и 4.2 - PullRequest
0 голосов
/ 17 января 2019

Я занимаюсь разработкой приложения для iOS, используя swift 4.0 (та же проблема возникает и в 4.2).

Я добавил расширение для Encodable

extension Encodable{

    func toDict() throws -> [String:Any]? {
        let jsonEncoder = JSONEncoder()
        let jsonData = try jsonEncoder.encode(self)
        do{
            return try JSONSerialization.jsonObject(with: jsonData, options: []) as? [String: Any]
        }
        catch{
            return nil
        }
    }
}

У меня есть экземпляр класса Encodable и класса со свойствами, которые также относятся к классу Encodable, и заметил, что при частом вызове instance.toDict() память, используемая моим приложением, значительно увеличивается. Это верно, даже если я не использую возвращаемый результат, это также верно, если я возвращаю ноль и игнорирую результат JSONSerialization.jsonObject.

Я уверен, что именно эта строка вызывает проблему (игнорирование результата и возврат nil по-прежнему вызывает проблему, а комментирование этой строки и возврат nil остановят увеличение памяти.

Память увеличивается все больше и больше с течением времени, и toDict() вызывается больше, в конечном итоге я использую 400 МБ менее чем за 10 минут.

Кто-нибудь сталкивался с этой проблемой? и есть ли решение?

1 Ответ

0 голосов
/ 25 апреля 2019

Может быть, я могу помочь. Я работал над проектом, который имеет модель класса Codable. Я думал, что все работает нормально, пока не понял, что приложение зависало из-за проблемы с памятью (более 1,2 ГБ) при попытке кодирования в цикле.

После отладки приложения я обнаружил, что проблема была в JSONEncoder, и после некоторого поиска в Google я обнаружил, что это ошибка, и решение, которое я нашел наиболее подходящим, заключается в использовании autoreleasepool. См. ЗДЕСЬ

в моем случае:

static func store<T: Encodable>(_ object: T, to directory: Directory, as fileName: String) throws {

    do{

        try autoreleasepool{

            let url = getURL(for: directory).appendingPathComponent(fileName, isDirectory: false)
            let encoder = JSONEncoder()

            let data = try encoder.encode(object)

            if FileManager.default.fileExists(atPath: url.path) {
                try FileManager.default.removeItem(at: url)
            }
            FileManager.default.createFile(atPath: url.path, contents: data, attributes: nil)

        }

    }
    catch {

        throw(error)

    }

}

После повторной отладки я вижу, что есть некоторые пики, но память стабилизируется.

...