Kev*_*inP 5 memory-leaks swift swiftui combine
在 xcode 中使用内存图调试器时,我看到了一些内存泄漏。Backtrace 没有直接链接到我的任何代码,而是通过跟踪猜测它的保存以假设它与组合和一些 DataTaskPublisher 相关。
接下来我检查了 Instruments 内部,在那里我也看到了一些内存泄漏。所有泄漏都在堆栈跟踪中提到“专门的静态 UIApplicationDelegate.main()”,但它并没有真正链接到可能导致内存泄漏的东西。
删除负责从 API 加载数据的 ViewModel 可以消除泄漏。内存图调试器显示了一个 dataTaskPublisher,所以这有点道理。
import Foundation
import Combine
enum API {
static func games() -> AnyPublisher<[GameResult], Error> {
let requestHeaderGames = gamesRequest()
return URLSession.shared.dataTaskPublisher(for: requestHeaderGames)
.map(\.data)
.decode(type: [GameResult].self, decoder: JSONDecoder())
.receive(on: DispatchQueue.main)
.eraseToAnyPublisher()
}
private static func gamesRequest() -> URLRequest {
let url = URL(string: "http://localhost:8080/api/games")!
var requestHeader = URLRequest.init(url: url)
requestHeader.httpBody =
"filter ..."
.data(using: .utf8, allowLossyConversion: false)
requestHeader.httpMethod = "POST"
requestHeader.setValue("application/json", forHTTPHeaderField: "Accept")
return requestHeader
}
}
struct GameResult: Decodable, Identifiable, Equatable, Hashable {
let id: Int
// ...
}
final class ViewModel: ObservableObject {
@Published private(set) var games: [GameResult] = []
private var subscriptions = Set<AnyCancellable>()
public func unsubscribe() -> Void {
subscriptions.forEach {
$0.cancel()
}
subscriptions.removeAll()
}
func load() -> Void {
API.games()
.sink(receiveCompletion: { _ in }, receiveValue: { [weak self] results in
self?.games = results
})
.store(in: &subscriptions)
}
}
Run Code Online (Sandbox Code Playgroud)
我已经花了很多时间来弄清楚是什么导致了这个泄漏,但我比其他任何事情都更困惑。CFString 不是我使用的任何东西。我也无法找出为什么我的代码似乎导致了这种泄漏。有什么我只是缺少的东西,或者有人可以通过给我一些建议来帮助我解决这个问题吗?
您发布的第一张图片似乎表明这是解码器发布者的问题。我会尝试几种不同的场景,看看我们是否可以通过解码来隔离问题:
enum API {
static var fakeGameData: Data {
let encoder = JSONEncoder()
return try! encoder.encode(fakeGames)
}
static var fakeGames: [GameResult] {
return [GameResult(id: 0), GameResult(id: 2), GameResult(id: 3)]
}
static func gamesFromData() -> AnyPublisher<[GameResult], Error> {
return Just(fakeGameData)
.decode(type: [GameResult].self, decoder: JSONDecoder())
.mapError({ $0 as Error })
.eraseToAnyPublisher()
}
static func gamesFromArray() -> AnyPublisher<[GameResult], Error> {
return Just(fakeGames)
.mapError({ $0 as Error })
.eraseToAnyPublisher()
}
}
Run Code Online (Sandbox Code Playgroud)
看看如果您订阅 API.gamesFromData() 会发生什么。如果仍然发现泄漏,则可能是解码器存在问题。如果不是,则更有可能是 dataTaskPublisher 出现问题。
然后,看看如果您订阅 API.gamesFromArray() 会发生什么。如果您仍然看到泄漏,那么您就知道问题不在于解码器发布者。
| 归档时间: |
|
| 查看次数: |
344 次 |
| 最近记录: |