微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

有或没有[弱自我]

如何解决有或没有[弱自我]

我遇到了一个非常奇怪的情况。我的服务器目前已关闭并收到 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)
})

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

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

let task = urlSession.dataTask(with: urlRequest) {data,error in
  if let response = response as? HTTPURLResponse,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()

decodeErrorMessage 方法

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

解决方法

问题在于,您将 customNetworkerCustomNetworker 设为局部变量,一旦该局部变量超出范围,您就会失去对它的强引用。当 dataRequest(input:) 方法使用 [weak self] 引用时,表示您也不希望 dataRequest(input:) 保留对此 CustomNetworker 实例的强引用。因此,在没有强引用的情况下,CustomNetworker 将被释放。

您有几个选择:

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

  2. 另一种替代方法是重构此代码,将这个网络请求例程 dataRequest(input:) 移动到某个更长寿的对象。

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

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

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

    然后您可以执行以下操作:

    NetworkManager.shared.performRequest(...) { [weak self] ... in
        ...
    }
    
  3. 另一种选择是保留对此 customNetworker 变量的强引用(例如,将其设为属性而不是局部变量)。这将防止 CustomNetworker 对象超出范围并变成 nil,因为没有对它的强引用。


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

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

,

这意味着无论 self 是什么,它都是一些您没有正确保留的对象,因此在联网发生之前它就已经不存在了。当您删除 weak self 时,您会创建一种使该对象保持活动状态的保留循环,但这只是掩盖了问题。您应该专注于 self 是如何创建和保留的,以及它为何如此迅速地消失。

,

我认为不可能在表达式中设置断点。您有一个带有复杂表达式的 if 语句,并尝试在其中设置断点并跟踪子表达式之一是否为真/或假。如果你想调试它,那么你需要把它分成几个 if 语句。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其他元素将获得点击?
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。)
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbcDriver发生异常。为什么?
这是用Java进行XML解析的最佳库。
Java的PriorityQueue的内置迭代器不会以任何特定顺序遍历数据结构。为什么?
如何在Java中聆听按键时移动图像。
Java“Program to an interface”。这是什么意思?