You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

解决在AppIntent中访问mainContext的Non-sendable类型警告

解决Widget中访问SwiftData ModelContext的Sendable警告

问题根源

警告的核心原因:

  • ModelContext并非Sendable类型,无法安全跨actor边界传递
  • modelContainer.mainContext被标记为@MainActor隔离属性,直接在自定义DataModel actor外部访问会触发跨actor的不安全访问检查

最佳解决方案:封装数据操作到DataModel内部

将添加Item的逻辑封装在DataModel actor内部,避免外部直接接触ModelContext,从根源上消除跨actor传递non-sendable类型的问题。

修改DataModel代码

import SwiftUI
import SwiftData

actor DataModel {
    struct TransactionAuthor {
        static let widget = "widget"
    }

    static let shared = DataModel()
    private init() {}
    
    nonisolated lazy var modelContainer: ModelContainer = {
        let modelContainer: ModelContainer
        do {
            modelContainer = try ModelContainer(for: Item.self)
        } catch {
            fatalError("Failed to create the model container: \(error)")
        }
        return modelContainer
    }()
    
    // 封装添加Item的方法,内部处理ModelContext操作
    func addNewItem() async {
        await MainActor.run {
            let newItem = Item(timestamp: Date())
            self.modelContainer.mainContext.insert(newItem)
            
            // 主动保存上下文,确保数据持久化
            do {
                try self.modelContainer.mainContext.save()
            } catch {
                print("Failed to save new item: \(error)")
            }
        }
    }
}

修改Intent代码

import AppIntents

struct AddNewItemIntent: AppIntent {
  static var title: LocalizedStringResource = "Add new item intent"

  func perform() async throws -> some IntentResult {
    print("AddNewItemIntent button tapped")
    // 调用封装好的方法,无需直接接触ModelContext
    await DataModel.shared.addNewItem()
    return .result()
  }
}

替代方案:在主actor上下文执行操作

如果不想封装方法,可以直接在MainActor.run中执行ModelContext操作,确保访问mainContext时处于主actor环境,避免跨actor访问:

import AppIntents

struct AddNewItemIntent: AppIntent {
  static var title: LocalizedStringResource = "Add new item intent"

  func perform() async throws -> some IntentResult {
    print("AddNewItemIntent button tapped")
    
    await MainActor.run {
        let newItem = Item(timestamp: Date())
        DataModel.shared.modelContainer.mainContext.insert(newItem)
        
        do {
            try DataModel.shared.modelContainer.mainContext.save()
        } catch {
            print("Save error: \(error)")
        }
    }
    
    return .result()
  }
}

方案说明

  • 第一种方案通过封装,将所有对ModelContext的操作限制在DataModel内部,外部只调用安全的actor方法,完全避免了跨actor传递non-sendable类型
  • 第二种方案确保mainContext的访问和操作都在主actor上下文完成,符合其@MainActor隔离的要求,消除了不安全访问的警告

两种方案都能适配Swift 6的严格Sendable检查,避免警告升级为错误。

内容的提问来源于stack exchange,提问作者appfrosch

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.19 12:51:00