如何解决有或没有[弱自我]
我遇到了一个非常奇怪的情况。我的服务器目前已关闭并收到 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)
}
}
解决方法
问题在于,您将 customNetworker
、CustomNetworker
设为局部变量,一旦该局部变量超出范围,您就会失去对它的强引用。当 dataRequest(input:)
方法使用 [weak self]
引用时,表示您也不希望 dataRequest(input:)
保留对此 CustomNetworker
实例的强引用。因此,在没有强引用的情况下,CustomNetworker
将被释放。
您有几个选择:
-
如果在
[weak self]
内的闭包中删除dataRequest(input:)
引用,那么它将保留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
,因为没有对它的强引用。
有点不相关,但是当您实例化 URLSession
对象时,您似乎正在创建一个 CustomNetworker
对象,并且随后从未使其无效。这会泄漏。您应该创建一个 URLSession
对象并将其用于所有后续网络请求。
如果您确实创建了多个 URLSession
对象,则必须在完成后使每个对象无效(例如,finishTasksAndInvalidate
),否则会泄漏。但是,如果您只有一个会话可以为所有未来的网络请求保持活动状态(这是首选),则没有必要。
这意味着无论 self
是什么,它都是一些您没有正确保留的对象,因此在联网发生之前它就已经不存在了。当您删除 weak self
时,您会创建一种使该对象保持活动状态的保留循环,但这只是掩盖了问题。您应该专注于 self
是如何创建和保留的,以及它为何如此迅速地消失。
我认为不可能在表达式中设置断点。您有一个带有复杂表达式的 if 语句,并尝试在其中设置断点并跟踪子表达式之一是否为真/或假。如果你想调试它,那么你需要把它分成几个 if 语句。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。