I discovered some memory leaks in my iOS app when it decodes server responses. These memory leaks don't happen all the time. I am using the following code to decode the response. The codes are inside a generic struct. T.self is also a struct not a class.
struct Response<T:Decodable> {
var value: T?
var result: ProcessResult<CustomError>
var request: TRequestHeader
init(_ request: TRequestHeader) {
self.request = request
result = .noDataReceived
}
init(_ request: TRequestHeader, _ responseData: Data) {
self.init(request)
do {
try autoreleasepool {
// parse the server response
if let dict = try JSONSerialization.jsonObject(with: responseData) as? [String:Any] {
var success = dict["success"] as? Bool ?? false
var dataDict: [String:Any]?
var dataArray: [Any]?
dataDict = dict["data"] as? [String:Any]
if dataDict == nil {
dataArray = dict["data"] as? [Any]
}
// now we can decode the JSON data
if success {
if let dict = dataDict {
if let data = try? JSONSerialization.data(withJSONObject: dict, options: []) {
let decoder = JSONDecoder()
if let decodedObj = try? decoder.decode(T.self, from: data) {
value = decodedObj
}
}
} else if let array = dataArray {
if let data = try? JSONSerialization.data(withJSONObject: array, options: []) {
let decoder = JSONDecoder()
if let decodedObj = try? decoder.decode(T.self, from: data) {
value = decodedObj
}
}
}
result = .success
}
}
}
} catch let error {
result = .failed(CustomError(code: 0, message: error.localizedDescription))
}
}
}
So the if let decodedObj = try? decoder.decode(T.self, from: data) causes the leak and I don't know how to prevent this. I covered the entire code block with try autoreleasepool { } but it didn't solve my problem.
I understand that it is not easy to understand what is causing the leak from this code snippet but when I googled JSONDecoder().decode memory leak issues I found too many complaints from other developers. Some says it is a bug in Swift and I can say Swift 5.0 didn't solve my problem. I have checked my Xcode's Swift version and it is 5.0.
Any comments and/or code shares about generic functions that does decoding server response highly appreciated. Thank you.
I came across a similar issue where I had a loop creating temporary objects using a JSONDecoder
. The temporary objects were not released so the memory usage of the command line tool I was developing kept increasing. I was able to resolve it using an autoreleasepool
. See https://medium.com/@itsachin523/understanding-autoreleasepool-in-swift-with-examples-5850d7ce8ed.