fix(concurrency): clear 4 Swift 6 warnings under default MainActor isolation
- ModelStore/FileVault: drop nonisolated(unsafe) on shared, mark all instance methods nonisolated (they only read filesystem); ModelKind enum also nonisolated - AIRuntime ↔ ModelStore cross-actor call resolved by the above - LLMSession: replace deprecated Device.setDefault(device:) with task-scoped Device.withDefaultDevice(.cpu, body:); wrap both load and generate so the TaskLocal propagates through ModelContainer.perform
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
import Foundation
|
||||
|
||||
enum ModelKind: String, CaseIterable {
|
||||
nonisolated enum ModelKind: String, CaseIterable {
|
||||
/// 与 HuggingFace mlx-community 仓库名一一对应,也是沙盒 Models/ 下的子目录名。
|
||||
case llm = "Qwen3-1.7B-4bit"
|
||||
case vl = "Qwen2.5-VL-3B-Instruct-4bit"
|
||||
@@ -21,10 +21,10 @@ enum ModelKind: String, CaseIterable {
|
||||
|
||||
/// `@unchecked Sendable`:rootURL 是 let,方法只读 filesystem(线程安全),
|
||||
/// 可被任意 actor / Task 跨边界访问。
|
||||
/// `nonisolated(unsafe) shared`:项目开启 `-default-isolation=MainActor` 后
|
||||
/// static 默认 MainActor 隔离,跨 actor 访问需要 await。这里手动 opt-out。
|
||||
/// 实例方法显式 `nonisolated`:项目开了 `SWIFT_DEFAULT_ACTOR_ISOLATION = MainActor`,
|
||||
/// 默认会把方法推到 MainActor,导致从 `AIRuntime` 等 actor 调用报错。
|
||||
final class ModelStore: @unchecked Sendable {
|
||||
nonisolated(unsafe) static let shared: ModelStore = {
|
||||
nonisolated static let shared: ModelStore = {
|
||||
do {
|
||||
let appSupport = try FileManager.default.url(
|
||||
for: .applicationSupportDirectory,
|
||||
@@ -46,16 +46,16 @@ final class ModelStore: @unchecked Sendable {
|
||||
try FileManager.default.createDirectory(at: rootURL, withIntermediateDirectories: true)
|
||||
}
|
||||
|
||||
func localURL(for kind: ModelKind) -> URL {
|
||||
nonisolated func localURL(for kind: ModelKind) -> URL {
|
||||
rootURL.appendingPathComponent(kind.rawValue, isDirectory: true)
|
||||
}
|
||||
|
||||
func isReady(_ kind: ModelKind) -> Bool {
|
||||
nonisolated func isReady(_ kind: ModelKind) -> Bool {
|
||||
let sentinel = localURL(for: kind).appendingPathComponent(kind.sentinelFilename)
|
||||
return FileManager.default.fileExists(atPath: sentinel.path)
|
||||
}
|
||||
|
||||
func totalBytes(for kind: ModelKind) -> Int {
|
||||
nonisolated func totalBytes(for kind: ModelKind) -> Int {
|
||||
let folder = localURL(for: kind)
|
||||
guard let enumerator = FileManager.default.enumerator(
|
||||
at: folder,
|
||||
@@ -71,7 +71,7 @@ final class ModelStore: @unchecked Sendable {
|
||||
}
|
||||
|
||||
/// Demo 现场旁路:从 Bundle 拷贝预装模型(W6 才真正使用,本周占位)
|
||||
func seedFromBundle(_ kind: ModelKind) throws {
|
||||
nonisolated func seedFromBundle(_ kind: ModelKind) throws {
|
||||
guard let bundleURL = Bundle.main.url(forResource: kind.rawValue, withExtension: nil) else {
|
||||
#if DEBUG
|
||||
assertionFailure("Bundle 缺少 \(kind.rawValue),检查资源是否加入 target")
|
||||
|
||||
Reference in New Issue
Block a user