Alamofire内存泄漏问题的Instruments解决方法

19

我正在尝试清除我的应用程序中的内存泄漏问题,但有几个问题我不太理解:

图片描述

  • 为什么在我启动应用程序后30秒会调用 Alamofire 函数 Request.serializeResponseJSON:我没有触摸任何东西或导航到任何地方,屏幕保持静态。

  • 为什么会出现内存泄漏?

  • 为什么我的代码存在内存泄漏问题?

当屏幕加载时,我也会遇到相同的内存泄漏问题。

我已经尝试过以下方法:

  • 自动释放池;

  • 以所有可能的方式向数组添加和初始化;

  • 将所有变量(类、函数)更改为可选/非可选/弱引用;

  • UIViewController 中初始化类;

  • 在主线程中初始化类;

  • 在互联网上搜索这些问题。

  • 使用 Xcode 内存工具,我发现它与 _ContiguousArrayStorage 有关,但我不理解它是什么以及它的实际作用。 图片描述

我已经没有任何想法了,希望能得到一些提示。

以下是所有相关代码:我的通用 API 请求:

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?)
    }
}

我的屏幕请求

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)
    }
}

我的类(我知道这种初始化方式有点不对,但我已经改成init(data: JSON)了 - 没有帮助:

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
}

这些泄漏的数组:

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
  }
}
1个回答

1
你尝试过将URLCache时间设置为请求吗?这将删除请求的缓存并释放内存。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接