带或不带[weak self]

  • 本文关键字:self weak 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)
})

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

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

问题是,你已经使customNetworker,CustomNetworker,一个局部变量,你失去了你的强引用,只要这个局部变量落在范围之外。当dataRequest(input:)方法使用[weak self]引用时,它表示您也不希望dataRequest(input:)保持对CustomNetworker实例的强引用。因此,如果没有强引用,CustomNetworker将被释放。

你有几个选择:

  1. 如果您在dataRequest(input:)内部的闭包中删除[weak self]引用,那么它将保留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,因为不再有对它的强引用。


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

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

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

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

最新更新