6

I am developing an iOS app, using swift 4.0 (4.2 has the same issue).

I added an extension to 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
        }
    }
}

I have an instance of and Encodable class that has properties that are also of an Encodable class and noticed that when calling instance.toDict() often, the memory that my app uses increases a lot. This is true even if I do not use the result that is returned, it is also true if I return nil and ignore the result of JSONSerialization.jsonObject.

I am sure it is this line that is causing the issue (ignoring the result and returning nil still causes the issue and commenting that line and returning nil will stop the memory increase.

The memory increases more and more as time passes and toDict() is called more, I eventually end up using 400MB in under 10 mins.

Has anyone encountered this issue? and is there a solution?

Dev138
  • 334
  • 1
  • 13

1 Answers1

2

Maybe I can help. I have been working on a project that has a Codable class model. I thought that everything was working fine until I realised that the app was crashing due to a memory issue (more than 1.2GB) when trying to encode in a loop.

After debugging the app i found that the issue was in the JSONEncoder and after some google search I found out that the is a bug and the solution that I found to work best was using autoreleasepool. See HERE

in my case:

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)

    }

}

After debugging again, I see that there are some peaks but the memory stabilises.

Reimond Hill
  • 4,278
  • 40
  • 52