JuicyFruit
JuicyFruit

Reputation: 2668

Alamofire memory leaks Instruments

I am trying to clean my app from memory leaks and I have a few problems understanding this

enter image description here

I get same leaks when the screen have loaded.

What I've tried so far:

I am out of any ideas what is wrong here. Any tips would be much appreciated.

Here is all related code: My general API request

public func requestWithLocation(_ httpmethod: Alamofire.HTTPMethod, URL: String, parameters: [String: AnyObject]?, completionHandler: @escaping CompletionHandler) -> (){
    var header: HTTPHeaders = [:]
    var location: [String: Double] = [:]
    let locationManager = CLLocationManager()

    if (CLLocationManager.authorizationStatus() == .authorizedWhenInUse
        || CLLocationManager.authorizationStatus() == .authorizedAlways) &&  locationManager.location != nil {
        location = [
            "lon" :  locationManager.location!.coordinate.longitude,
            "lat" :  locationManager.location!.coordinate.latitude
        ]
    }

    if User.sharedInstance.token != "" {
        header["Authorization"] = User.sharedInstance.token
    }

    var parametersWithLocation = parameters ?? [:]
    parametersWithLocation["location"] = location as AnyObject

    Alamofire.request("\(serverAddress)/\(URL)", method: httpmethod, parameters: parametersWithLocation, encoding: JSONEncoding.default, headers: header).validate().responseJSON { response in
        var data: JSON?

        if response.result.value != nil {
            data = JSON(response.result.value!)
        }
        if User.sharedInstance.token == "" {
            User.sharedInstance.token =  response.response?.allHeaderFields["Authorization"] as! String
        } else {
            if let header = response.response?.allHeaderFields["Authorization"] as? String {
                if User.sharedInstance.token != header {
                    User.sharedInstance.token = header
                }
            }
        }
        completionHandler(data, response.result.error as NSError?)
    }
}

My screen request

class func requestMainScreen(handler: @escaping ([ShortRestaurant], [ShortRestaurant], [ShortRestaurant]) -> ()) {
    var dataForBestChoise: [ShortRestaurant] = []
    var dataForTop: [ShortRestaurant] = []
    var dataForNearest: [ShortRestaurant] = []

    let group = DispatchGroup()
    group.enter()

    APIModel.sharedInstance.requestWithLocation(.post, URL: "restaurants/near", parameters: nil, completionHandler: {(data, error) in

        guard let `data` = data else {
            group.leave()
            return
        }
        for JSON in data["restaurants"].arrayValue {
            dataForNearest.append(ShortRestaurant.initFromJSON(JSON)) //here is leak
        }
        group.leave()
    })

    group.enter()
    APIModel.sharedInstance.requestWithLocation(.post, URL: "restaurants/top", parameters: nil, completionHandler: {(data, error) in
        guard let `data` = data else {
            group.leave()
            return
        }
        for JSON in data["restaurants"].arrayValue {
            dataForTop.append(ShortRestaurant.initFromJSON(JSON))//here is leak
        }
        group.leave()
    })

    group.enter()
    APIModel.sharedInstance.requestWithLocation(.post, URL: "restaurants/personal", parameters: nil, completionHandler: {(data, error) in

        guard let `data` = data else {
            group.leave()
            return
        }

        for JSON in data["restaurants"].arrayValue {
             dataForBestChoise.append(ShortRestaurant.initFromJSON(JSON)) //here is leak
        }
        group.leave()
    })

    group.notify(queue: DispatchQueue.main) {
        handler(dataForBestChoise, dataForTop, dataForNearest)
    }
}

My classes (I know this kind of initialisation is kinda wrong, but I'd changed to init(data: JSON) - did not help:

class func initFromJSON(_ data: JSON) -> ShortRestaurant {
    let restaurant = ShortRestaurant()
    restaurant.id                       = data["id"].stringValue
    restaurant.name                     = data["name"].stringValue
    restaurant.image                    = data["img"].stringValue
    restaurant.description              = data["shortDesc"].stringValue
    restaurant.nameOfMetrostatin        = data["address"]["metro"]["name"].stringValue
    restaurant.mapType                  = data["mapType"].stringValue
    restaurant.address                  = data["address"]["street"].stringValue
    restaurant.longitude                = data["address"]["location"][0].doubleValue
    restaurant.latitude                 = data["address"]["location"][1].doubleValue
    restaurant.phone                    = data["phone"].stringValue
    restaurant.workTime                 = data["currentWork"].stringValue
    restaurant.avarageBill              = data["price"].stringValue
    restaurant.peopleInfo               = data["croud"].stringValue
    restaurant.rating                   = data["rating"].stringValue
    restaurant.ratingTrend              = data["trend"].stringValue
    restaurant.distance                 = data["distance"].doubleValue
    restaurant.isFavourited             = data["isFavourited"].bool ?? false
    restaurant.specialOfferDescription  = data["discounts"]["name"].string
    restaurant.specialOfferName         = data["discounts"]["type"].string
    restaurant.alertText                = data["label"]["name"].string
    restaurant.alertIcon                = data["label"]["type"].string
    restaurant.alertBackground          = data["label"]["color"].string
    restaurant.avaliableDates           = ReservationSchedule.initArrayFrom(data: data["availableDates"])
    restaurant.avaliableTimes           = data["scheduleRes"].arrayObject as? [String] ?? []
    restaurant.doesHaveDiscount         = data["discounts"]["id"].string != nil
    restaurant.doesHaveEvent            = data["events"]["id"].string != nil
    restaurant.weeklyTop                = data["weeklyTop"].bool ?? false
    restaurant.monthlyTop               = data["monthlyTop"].bool ?? false
    restaurant.yearTop                  = data["yearTop"].bool ?? false
    restaurant.isActive                 = data["isActive"].bool ?? true
    return restaurant
}

Array of these leaks:

class ReservationSchedule {
  var description: String
  var data: String
  var dayTitle: String
  var fullTitle: String

  init(data: JSON) {
    self.data = data["value"].stringValue
    self.dayTitle = data["day"].stringValue
    self.description = data["label"].stringValue
    self.fullTitle = data["title"].stringValue
  }

  class func initArrayFrom(data: JSON) -> [ReservationSchedule] {
    var schedule: [ReservationSchedule] = []
    for day in data.arrayValue {
        schedule.append(ReservationSchedule.init(data: day)) //here is leak
    }
    return schedule
  }
}

Upvotes: 19

Views: 1212

Answers (1)

Albi
Albi

Reputation: 1855

Have you tried setting URLCache time to request, This will remove the the cache of request and free's the memory

Upvotes: 1

Related Questions