Reputation: 51
Im using AFNetworking in my project. When I try to find the memory leaks using instruments, its showing AFNetworking as reasons for memory leak. I'm creating a model class and within that class I'm calling the AFNetworking. Call to API is done from Viewcontroller to model class.Please help me how to fix this issue.
My coding pattern is adding below.
Class myViewController:UIViewcontroller{
override func viewDidLoad() {
super.viewDidLoad()
//apiCall
myModel.apiCallFuncT("value"){ (success) in
}
}
}
Class myModel{
var somevariable:String
class apiCallFuncT(parameters:string,completionHandler:@escaping(_ success:Bool)->Void){
//here Im calling the AFNetworking class. Im adding the call below.
ServiceManager.getDataFromNewServiceSolOne(serviceName: URL + "\(apiName)", parameters: param , success: { (result) in
completion(true)
})
}
//This is the serviceManger I'm calling from all models I have for api Calls.
class ServiceManager: NSObject {
static var sharedManager = AFHTTPSessionManager()
class func getDataFromNewServiceSolOne(serviceName: String, parameters : [String : String]?, success:@escaping (_ result: AnyObject) -> Void, failure :@escaping (_ error : NSError) -> Void) {
let manager = AFHTTPSessionManager(baseURL: NSURL(string: URL)! as URL)
manager.responseSerializer.acceptableContentTypes = ["text/html", "application/json"]
manager.post(serviceName, parameters: parameters, progress: { (progress) in
}, success: { (task, result) in
success(result as AnyObject)
}) { (task, error) in
failure(error as NSError)
}
}
}
Upvotes: 2
Views: 251
Reputation: 438082
To diagnose these issues, the “Debug Memory Graph” feature with “Malloc Stack” option is the first tool for which we reach. See How to debug memory leaks when Leaks instrument does not show them?
Anyway, when we run that, we can see that the problem is not in your use of the API. You don’t have any strong reference cycles in your code. In this example, we don’t see any of our app’s objects (other than app and scene delegates) in the panel on the left (because I dismissed the custom view controller that initiated the request). So that’s great.
So, what’s going on? The issue is the cycle between AFHTTPSessionManager
and its NSURLSession
. Unlike most delegates, NSURLSession
keeps a strong reference to its delegate. As the documentation says:
The session object keeps a strong reference to this delegate until your app exits or explicitly invalidates the session. If you do not invalidate the session, your app leaks memory until it exits.
So, you have two possible solutions:
Invalidate the session when the request is done. Call finishTasksAndInvalidate
:
class func getDataFromNewServiceSolOne(serviceName: String, parameters: [String: String]?, success: @escaping (_ result: AnyObject) -> Void, failure: @escaping (_ error: NSError) -> Void) {
let manager = AFHTTPSessionManager(baseURL: URL(string: baseUrlString))
manager.post(serviceName, parameters: parameters, headers: nil, progress: { _ in
// this is intentionally blank
}, success: { task, result in
success(result as AnyObject)
}, failure: { task, error in
failure(error as NSError)
})
manager.session.finishTasksAndInvalidate() // add this line
}
The other approach is to not create a separate AFHTTPSessionManager
for every request, but rather instantiate it once and then store it in a property. Then you don’t need to worry about invalidating it. Also, there is a certain amount of overhead in creating sessions, so we often instantiate a single session, and then perform many requests using that. And then you don’t have to worry about creating and invalidating a new session for every request.
Upvotes: 2