2

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)
        }
    }
}
Sudheer Kolasani
  • 283
  • 5
  • 28
  • Is there any particular reason you are using AFNetworking? Why not [URLSession](https://developer.apple.com/documentation/foundation/urlsession) from Apple or [Alamofire](https://github.com/Alamofire/Alamofire)? Also, please try to include a reproducible example in your code. – Kamran Oct 15 '19 at 13:09
  • I just joined the team only. AF is added a long back ago. Now project is very big and its difficult to change to another. Above is exactly what I'm using. I can't share urls as I'm in an organisation.Can you help me. @Kamran – Jaisan Mathew Oct 25 '19 at 12:36

1 Answers1

2

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?

enter image description here

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:

  1. 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
    }
    
  2. 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.

Rob
  • 415,655
  • 72
  • 787
  • 1,044