有或没有[弱自我]

kon*_*nya 2 swift

我的情况很奇怪。我的服务器当前已关闭并收到 503 http 状态代码。根据给定的代码如下,代码进入 if 条件,但是当我将调试点置于let error = self?.decodeErrorMessage(data: data, statusCode: response.statusCode). 然后它从 if 条件跳转并执行 else if 条件。

ClientViewModel.swift

let networkRequest = CustomNetworkRequest(headers: headers, httpMethod: .get, httpBody: nil, parameters: nil, url: url)

let customNetworker = CustomNetworker(urlSession: URLSession(configuration: config))
  customNetworker.dataRequest(networkRequest, successHandler: {[weak self] data in
    self?.parseData(data)
    completion(nil)
  }, failureHandler: { [weak self] error in
    completion(error)
})
Run Code Online (Sandbox Code Playgroud)

CustomNetworker.swift

final class CustomNetworker {
  private let urlSession: URLSession

  public init(urlSession: URLSession) {
    self.urlSession = urlSession
  }
  func dataRequest(input parameters here) {
    let task = urlSession.dataTask(with: urlRequest) {[weak self] data, response, error in
     if let response = response as? HTTPURLResponse , 300...599 ~= response.statusCode,
     let data = data,
     let error = self?.decodeErrorMessage(data: data, statusCode: response.statusCode) {
    failureHandler(error)
    } else if let error = error {
     failureHandler(error)
    } else if let data = data {
      successHandler(data)
    } else {
      failureHandler(error)
    }
  }
  task.resume()
  }
}
Run Code Online (Sandbox Code Playgroud)

但是,如果我删除[weak self]它,它就会按预期工作,它会调用该方法。我该如何正确解决问题?

let task = urlSession.dataTask(with: urlRequest) {data, response, error in
  if let response = response as? HTTPURLResponse , 300...599 ~= response.statusCode,
    let data = data,
    let error = self.decodeErrorMessage(data: data, statusCode: response.statusCode) {
    failureHandler(error)
  }
  else if let error = error {
    failureHandler(error)
  } else if let data = data {
    successHandler(data)
  } else {
    failureHandler(error)
    )
  }
}
task.resume()
Run Code Online (Sandbox Code Playgroud)

解码错误消息方法

private func decodeErrorMessage(data: Data, statusCode: Int) -> CustomError?  {
   // not coming into this method
    if let errorData = try? JSONDecoder.convertFromSnakeCaseDecoder.decode(CustomServiceError.self, from: data) as CustomServiceError? {
      if let errorData = errorData {
        return formCustomError(something here)
      }
      return CustomError.genericError(debugMessage: debugMessage, sourceError: nil)
    } else if let errorMessage = StatusCode(rawValue: statusCode) {
      let debugMessage = String(data:data, encoding: .utf8)
      return formCustomError(something here)
    } else {
      let debugMessage = String(data:data, encoding: .utf8)
      return formCustomError(something here)
    }
  }
Run Code Online (Sandbox Code Playgroud)

Rob*_*Rob 5

问题是您\xe2\x80\x99已经创建了customNetworker, CustomNetworker, 局部变量,并且一旦该局部变量超出范围,您就会失去对它的强引用。当该dataRequest(input:)方法使用[weak self]引用时,它表示您也不想dataRequest(input:)保留对此实例的强引用CustomNetworker。结果,在没有强有力的参考资料的情况下,CustomNetworker将被释放。

\n

您有几种选择:

\n
    \n
  1. 如果您删除[weak self]闭包内部的引用dataRequest(input:),那么它将保留CustomNetworker直到闭包运行。只要您不\xe2\x80\x99t 将此failureHandler(和其他闭包)保存为存储属性,就应该没问题。但是不要\xe2\x80\x99t 只是抛出一个,[weak self]因为你在某处读到应该始终使用弱引用。在需要避免强引用循环的地方使用弱引用,但这里的情况似乎并非如此。

    \n
  2. \n
  3. 另一种选择是重构此代码,将此网络请求例程移动dataRequest(input:)到一些寿命更长的对象。

    \n

    例如,我们经常有一个长期存在的网络管理器对象,它维护URLSession并具有所有这些与网络相关的方法。然后,假设您\xe2\x80\x99在其他地方保留对此网络管理器实例的强引用,则\xe2\x80\x99不需要担心该对象在超出范围时被释放。这也使您不必为每个请求传递URLSession对象。无论如何,调用者不应该处理这些URLSession实例。

    \n

    例如,我经常使用单例网络层(类似于URLSession.shared模式):

    \n
    final class NetworkManager {\n    static let shared = NetworkManager()\n\n    private var session: URLSession = .shared // or create and configure this session as you need; but one session object is all you need\n\n    private init() { }\n\n    @discardableResult\n    func performRequest(...) -> URLSessionTask {\n        ...\n        let task = session.dataTask(...) { [weak self] data, response, error in\n            ...\n        }\n        task.resume()\n        return task\n    }\n}\n
    Run Code Online (Sandbox Code Playgroud)\n

    然后你可以做这样的事情:

    \n
    NetworkManager.shared.performRequest(...) { [weak self] ... in\n    ...\n}\n
    Run Code Online (Sandbox Code Playgroud)\n
  4. \n
  5. 另一种选择是仅保留对此customNetworker变量的强引用(例如,使其成为属性而不是局部变量)。这将防止CustomNetworker对象超出范围并nil因为不再有对它的强引用而成为对象。

    \n
  6. \n
\n
\n

有点不相关,但看起来您URLSession在实例化CustomNetworker对象时正在创建一个对象,并且随后永远不会使其无效。这会泄漏。您应该创建一个URLSession对象并将其用于所有后续网络请求。

\n

如果您确实创建了多个URLSession对象,那么当您使用完它时,您必须使每个对象无效(例如,finishTasksAndInvalidate),否则就会泄漏。但是,如果您只有一个会话,并为所有未来的网络请求保持活动状态(这是首选),那么就没有必要。

\n