我有一个很奇怪的情况。我的服务器目前关闭并获得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
将被释放。
你有几个选择:
-
如果您在
dataRequest(input:)
内部的闭包中删除[weak self]
引用,那么它将保留CustomNetworker
直到闭包运行。只要不将这个failureHandler
(和其他闭包)保存为存储属性,就不会有问题。但是不要因为你在某处读到应该总是使用弱引用而抛出[weak self]
。在需要避免强引用循环的地方使用弱引用,在这里似乎不是这种情况。 -
另一种选择是重构这段代码,将这个网络请求例程
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 ... }
-
另一种选择是保持对这个
customNetworker
变量的强引用(例如使其成为属性而不是局部变量)。这将防止CustomNetworker
对象脱离作用域而变成nil
,因为不再有对它的强引用。
有点不相关,但是当您实例化CustomNetworker
对象时,看起来您正在创建一个URLSession
对象,并且随后从未使其无效。这个会漏的。您应该创建一个单独的URLSession
对象,并将其用于所有后续的网络请求。
如果您确实创建了多个URLSession
对象,您必须在使用它(例如finishTasksAndInvalidate
)时使每个对象无效,否则您将会泄漏。但是,如果您只有一个会话,您将为所有未来的网络请求保持活动(这是首选),那么这是没有必要的。
这意味着无论self
是什么,它都是您没有正确保留的某个对象,因此在联网发生之前它就不存在了。当您删除weak self
时,您创建了一种保留循环,使该对象保持活动状态,但这仅仅掩盖了问题。你应该专注于self
是如何创建和保留的,以及为什么它这么快就消失了。
我认为在表达式内设置断点是不可能的。你有if语句与一个复杂的表达式,并试图设置断点在其中,并跟踪如果一个子表达式是真/假。如果你想调试它,那么你需要把它分成几个If语句。