我的情况很奇怪。我的服务器当前已关闭并收到 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)
问题是您\xe2\x80\x99已经创建了customNetworker, CustomNetworker, 局部变量,并且一旦该局部变量超出范围,您就会失去对它的强引用。当该dataRequest(input:)方法使用[weak self]引用时,它表示您也不想dataRequest(input:)保留对此实例的强引用CustomNetworker。结果,在没有强有力的参考资料的情况下,CustomNetworker将被释放。
您有几种选择:
\n如果您删除[weak self]闭包内部的引用dataRequest(input:),那么它将保留CustomNetworker直到闭包运行。只要您不\xe2\x80\x99t 将此failureHandler(和其他闭包)保存为存储属性,就应该没问题。但是不要\xe2\x80\x99t 只是抛出一个,[weak self]因为你在某处读到应该始终使用弱引用。在需要避免强引用循环的地方使用弱引用,但这里的情况似乎并非如此。
另一种选择是重构此代码,将此网络请求例程移动dataRequest(input:)到一些寿命更长的对象。
例如,我们经常有一个长期存在的网络管理器对象,它维护URLSession并具有所有这些与网络相关的方法。然后,假设您\xe2\x80\x99在其他地方保留对此网络管理器实例的强引用,则\xe2\x80\x99不需要担心该对象在超出范围时被释放。这也使您不必为每个请求传递URLSession对象。无论如何,调用者不应该处理这些URLSession实例。
例如,我经常使用单例网络层(类似于URLSession.shared模式):
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}\nRun Code Online (Sandbox Code Playgroud)\n然后你可以做这样的事情:
\nNetworkManager.shared.performRequest(...) { [weak self] ... in\n ...\n}\nRun Code Online (Sandbox Code Playgroud)\n另一种选择是仅保留对此customNetworker变量的强引用(例如,使其成为属性而不是局部变量)。这将防止CustomNetworker对象超出范围并nil因为不再有对它的强引用而成为对象。
有点不相关,但看起来您URLSession在实例化CustomNetworker对象时正在创建一个对象,并且随后永远不会使其无效。这会泄漏。您应该创建一个URLSession对象并将其用于所有后续网络请求。
如果您确实创建了多个URLSession对象,那么当您使用完它时,您必须使每个对象无效(例如,finishTasksAndInvalidate),否则就会泄漏。但是,如果您只有一个会话,并为所有未来的网络请求保持活动状态(这是首选),那么就没有必要。
| 归档时间: |
|
| 查看次数: |
824 次 |
| 最近记录: |