fix(swift): 清理并发与废弃 API 告警

This commit is contained in:
ysicing committed 2026-09-23 10:27:14 +08:00
1 parent a4b44a64fc
commit f34ba88db9
6 files changed
+34 -12

No files matched your search

@@ -34,9 +34,9 @@ final class StatusPanel: NSPanel {
defer: true)
// 打开时按平铺布局测出的高度只是起点:真实内容会随数据刷新变高变矮,由滚动区域上报差值再校正
makeContent = { [weak self] in
NSHostingView(rootView: content().environment(\.reportPopoverOverflow) { overflow in
NSHostingView(rootView: content().environment(\.reportPopoverOverflow, PopoverOverflowReporter { overflow in
self?.adjustHeight(by: overflow)
})
}))
}
isFloatingPanel = true
level = .statusBar
@@ -113,7 +113,7 @@ struct TimedLineChart: View {
var grid = false
var height: CGFloat = DS.Size.chartHeight
static let gapLimit: TimeInterval = 10
nonisolated static let gapLimit: TimeInterval = 10
var body: some View {
Canvas { context, size in
@@ -143,7 +143,7 @@ struct TimedLineChart: View {
}
/// 落在 [end − duration, end] 内的采样换算成坐标(0 在下、1 在上),按间隔断开成若干段
static func segments(_ points: [TimedValue], duration: TimeInterval, end: Date, in size: CGSize) -> [[CGPoint]] {
nonisolated static func segments(_ points: [TimedValue], duration: TimeInterval, end: Date, in size: CGSize) -> [[CGPoint]] {
let start = end.addingTimeInterval(-duration)
let inset = DS.Size.chartLine
let usable = size.height - inset * 2
@@ -584,6 +584,7 @@ struct ScoreBand: View {
private func marker(width: CGFloat) -> some View {
let color = DS.Grade.color(for: clamped)
let grade = DS.Grade.bands.first { clamped < $0.upper }?.grade ?? "A+"
let markerOffset = width * CGFloat(clamped) / 100
return VStack(spacing: 0) {
Text(verbatim: grade)
.dsFont(.xs, weight: .semibold)
@@ -594,7 +595,7 @@ struct ScoreBand: View {
Triangle().fill(color).frame(width: DS.Space.s2, height: DS.Space.s1)
}
.fixedSize()
.alignmentGuide(.leading) { dimensions in dimensions.width / 2 - width * CGFloat(clamped) / 100 }
.alignmentGuide(.leading) { dimensions in dimensions.width / 2 - markerOffset }
}
}
@@ -1,7 +1,27 @@
import Foundation
import Localization
import Metrics
import SwiftUI
/// 用独立身份包装不可比较的闭包,避免 SwiftUI 把无关环境刷新都视为回调变化。
struct PopoverOverflowReporter: Equatable, Sendable {
private let id = UUID()
private let action: @MainActor @Sendable (CGFloat) -> Void
init(_ action: @escaping @MainActor @Sendable (CGFloat) -> Void) {
self.action = action
}
@MainActor
func callAsFunction(_ overflow: CGFloat) {
action(overflow)
}
static func == (lhs: Self, rhs: Self) -> Bool {
lhs.id == rhs.id
}
}
/// ImageRenderer 无法渲染 ScrollView 等 AppKit 承载的控件,截图模式下改用平铺布局。
extension EnvironmentValues {
@Entry var isSnapshot = false
@@ -10,7 +30,7 @@ extension EnvironmentValues {
/// 菜单栏弹窗:区块去掉卡片底色,用细分隔线隔开,排得更紧凑
@Entry var isPopover = false
/// 菜单栏弹窗:滚动内容的实际高度比可视区域高出(负数为矮出)多少,交给面板调整窗口高度
@Entry var reportPopoverOverflow: (@MainActor @Sendable (CGFloat) -> Void)? = nil
@Entry var reportPopoverOverflow: PopoverOverflowReporter?
}
// MARK: - 卡片
@@ -62,7 +62,7 @@ public final class EgressController {
let environment = await Self.readEnvironment()
self.environment = environment
let hits = await EgressProber.measure(interfaceName: environment.physicalInterface) { done in
Task { @MainActor [weak self] in self?.progress = done }
Task { @MainActor in self.progress = done }
}
let analysis = EgressAnalysis.evaluate(hits, environment: environment)
let geo = await lookUpGeo(hits: hits, analysis: analysis, interfaceName: environment.physicalInterface)
@@ -257,8 +257,9 @@ public final class ProcessExplainer {
nonisolated private static func executablePath(pid: Int32) -> String? {
var buffer = [CChar](repeating: 0, count: 4 * Int(MAXPATHLEN))
guard proc_pidpath(pid, &buffer, UInt32(buffer.count)) > 0 else { return nil }
return String(cString: buffer)
let length = proc_pidpath(pid, &buffer, UInt32(buffer.count))
guard length > 0 else { return nil }
return buffer.withUnsafeBytes { String(decoding: $0.prefix(Int(length)), as: UTF8.self) }
}
}
@@ -90,9 +90,9 @@ public final class SpeedTestController {
liveBitsPerSecond = 0
broadbandTask = Task { [limit] in
let result = await BroadbandTest.run(limit: limit) { stage in
Task { @MainActor [weak self] in self?.broadbandStage = stage; self?.liveBitsPerSecond = 0 }
Task { @MainActor in self.broadbandStage = stage; self.liveBitsPerSecond = 0 }
} progress: { speed, _ in
Task { @MainActor [weak self] in self?.liveBitsPerSecond = speed }
Task { @MainActor in self.liveBitsPerSecond = speed }
}
guard !Task.isCancelled else { return stopBroadband() }
broadband = result
@@ -217,7 +217,7 @@ public final class SpeedTestController {
liveBitsPerSecond = 0
downloadTask = Task { [limit] in
let result = await ThroughputProbe.download(node.downloadURL, limit: limit) { speed, _ in
Task { @MainActor [weak self] in self?.liveBitsPerSecond = speed }
Task { @MainActor in self.liveBitsPerSecond = speed }
}
guard !Task.isCancelled else {
downloadingNode = nil