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

SwiftData操作ChatMessage报错:无法打开default.store或表不存在

问题:SwiftData中ChatMessage模型存储/查询失败,Product功能正常

错误现象

存储或查询ChatMessage时出现以下两类错误:

Query encountered an error: Error Domain=NSCocoaErrorDomain Code=256 "无法打开文件“default.store”。"

error: SQLCore dispatchRequest: exception handling request: <NSSQLFetchRequestContext: 0x3000eb800> , I/O error for database at /var/mobile/Containers/Data/Application/BE6DA08B-F6D6-4A52-9BCC-FD69F25A63F8/Library/Application Support/default.store. SQLite error code:1, 'no such table: ZCHATMESSAGE' with userInfo of {
NSFilePath = "/var/mobile/Containers/Data/Application/BE6DA08B-F6D6-4A52-9BCC-FD69F25A63F8/Library/Application Support/default.store";
NSSQLiteErrorDomain = 1;
}

相关代码

ChatMessage.swift

import Foundation
import SwiftData

// Define a ChatMessage model for storing chat history
@Model
final class ChatMessage {
    var id: UUID
    var content: String
    var sender: String // "user" or "ai"
    var timestamp: Date

    // Custom initializer for ChatMessage
    init(content: String, sender: String, timestamp: Date = Date()) {
        self.id = UUID()
        self.content = content
        self.sender = sender
        self.timestamp = timestamp
    }
}

ChatView.swift

import SwiftUI
import Foundation
import SwiftData

@MainActor
struct ChatView: View {
    @Environment(\.modelContext) private var modelContext
    
    // State properties to hold user input and AI response
    @State private var userMessage: String = ""
    @State private var aiResponse: String = "Type a message and press 'Send' to start."
    @State private var products: [Product] = []
    @State private var isLoading: Bool = false
    @Query(sort: \ChatMessage.timestamp, order: .forward) private var chatMessages: [ChatMessage]
    
    var body: some View {
        VStack {
            // Display chat history in a list
            ScrollViewReader { proxy in
                ScrollView {
                    VStack(spacing: 10) {
                        ForEach(chatMessages) { message in
                            HStack {
                                if message.sender == "user" {
                                    Spacer()
                                    Text(message.content)
                                        .padding()
                                        .background(Color.red)
                                        .foregroundColor(.white)
                                        .cornerRadius(10)
                                } else {
                                    Text(message.content)
                                        .padding()
                                        .background(Color(.secondarySystemBackground))
                                        .cornerRadius(10)
                                    Spacer()
                                }
                            }
                        }
                    }
                    .padding(.horizontal)
                }
                .onChange(of: chatMessages.count) {
                    if let lastMessage = chatMessages.last {
                        proxy.scrollTo(lastMessage.id, anchor: .bottom)
                    }
                }
            }
            
            Spacer()
            
            // Text input and send button at the bottom of the screen
            HStack {
                TextField("Enter your message", text: $userMessage, onCommit: {
                    // Send message when user presses return
                    Task {
                        await sendChatRequest()
                    }
                })
                .textFieldStyle(RoundedBorderTextFieldStyle())
                .padding(.horizontal)
                
                // Dynamic button: Show ProgressView when loading, otherwise show send button
                if isLoading {
                    ProgressView()
                        .padding(.trailing, 10)
                } else {
                    Button(action: {
                        Task {
                            await sendChatRequest()
                        }
                    }) {
                        Image(systemName: "paperplane.fill")
                            .foregroundStyle(.white)
                            .padding(7)
                            .background(Color.red)
                            .cornerRadius(5)
                    }
                    .padding(.trailing, 10)
                }
            }
            .padding(.bottom)
        }
        .task {
            // Fetch data when the view appears
            await fetchProducts()
        }
    }
    
    // Function to fetch products from the Core Data context
    private func fetchProducts() async {
        do {
            let fetchDescriptor: FetchDescriptor<Product> = FetchDescriptor()
            products = try modelContext.fetch(fetchDescriptor)
        } catch {
            aiResponse = "Error fetching data: \(error.localizedDescription)"
        }
    }
    
    // Function to handle sending the chat request to the AI
    private func sendChatRequest() async {
        guard !userMessage.isEmpty else {
            let aiChatMessage = ChatMessage(content: "Please enter a message before sending", sender: "ai")
            modelContext.insert(aiChatMessage)
            return
        }
        
        // Create a new ChatMessage for the user's message and save it
        let userChatMessage = ChatMessage(content: userMessage, sender: "user")
        modelContext.insert(userChatMessage)
        
        // Set loading state to true
        isLoading = true
        
        // Fetch AI summary based on user message and fetched products
        if let aiResponseText = await chatBasedOnHistory(message: userMessage, products: products) {
            let aiChatMessage = ChatMessage(content: aiResponseText, sender: "ai")
            modelContext.insert(aiChatMessage)
        } else {
            let aiChatMessage = ChatMessage(content: "Failed to generate summary.", sender: "ai")
            modelContext.insert(aiChatMessage)
        }
        
        do {
            try modelContext.save()
        } catch {
            print("Failed to save context: \(error.localizedDescription)")
        }
        
        // Clear the text field after sending the message
        userMessage = ""
        
        // Reset loading state
        isLoading = false
        
        print("Number of messages: \(chatMessages.count)")
        for message in chatMessages {
            print("Message: \(message.content), Sender: \(message.sender)")
        }
    }
}

AIController.swift

// Function to send the POST request and handle the response
func getAISummary(jsonString: String) async -> String? {
    let parameters = [
      "model": "llama-3.1-sonar-small-128k-online",
      "messages": [
        [
          "role": "system",
          "content": "Generate a concise summary of the overall quality and healthiness of the product based on the following product information."
        ],
        [
          "role": "user",
          "content": jsonString
        ]
      ],
      "return_citations": true
    ] as [String : Any?]

    do {
        let postData = try JSONSerialization.data(withJSONObject: parameters, options: [])
        let url = URL(string: "https://api.perplexity.ai/chat/completions")!
        var request = URLRequest(url: url)
        request.httpMethod = "POST"
        request.timeoutInterval = 10
        request.allHTTPHeaderFields = [
            "accept": "application/json",
            "content-type": "application/json",
            "authorization": "// Secret Key"
        ]
        request.httpBody = postData

        let (data, _) = try await URLSession.shared.data(for: request)
        
        // Parse the JSON response to extract the generated summary
        if let responseJson = try JSONSerialization.jsonObject(with: data, options: []) as? [String: Any],
           let choices = responseJson["choices"] as? [[String: Any]],
           let message = choices.first?["message"] as? [String: Any],
           let content = message["content"] as? String {
            return content
        }
    } catch {
        print("Error during the request: \(error.localizedDescription)")
    }
    
    return nil
}

// Function to generate a summary using AI based on product history
func chatBasedOnHistory(message: String, products: [Product]) async -> String? {
    // Convert products to a JSON-compatible dictionary or array
    let foodHistory: [[String: Any]] = products.map { product in
        return [
            "name": product.name,
            "brand": product.brand,
            "quantity": product.quantity,
            "ingredients": product.ingredients,
            "nutritionScore": product.nutritionScore,
        ]
    }

    do {
        // Convert food history to JSON string
        let foodHistoryJSONData = try JSONSerialization.data(withJSONObject: foodHistory, options: [])
        let foodHistoryJSONString = String(data: foodHistoryJSONData, encoding: .utf8) ?? ""

        // Prepare parameters for the API request
        let parameters: [String: Any] = [
            "model": "llama-3.1-sonar-small-128k-online",
            "messages": [
                [
                    "role": "system",
                    "content": message
                ],
                [
                    "role": "user",
                    "content": "This is information on what I have eaten in the past: \(foodHistoryJSONString). \n\nKeep in mind that this is an app where the user can scan products and view their nutritional value. They can also keep a log of what they have eaten and see how many calories they have eaten this week and how much sugar they have eaten in the past week. Try to reccomend the user to use different parts of the app."
                ]
            ],
            "return_citations": true
        ]

        let postData = try JSONSerialization.data(withJSONObject: parameters, options: [])

        // Create the API request
        let url = URL(string: "https://api.perplexity.ai/chat/completions")!
        var request = URLRequest(url: url)
        request.httpMethod = "POST"
        request.timeoutInterval = 10
        request.allHTTPHeaderFields = [
            "accept": "application/json",
            "content-type": "application/json",
            "authorization": "Bearer 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" // Use your actual API key
        ]
        request.httpBody = postData

        // Perform the API request
        let (data, response) = try await URLSession.shared.data(for: request)

        // Check for successful response status
        if let httpResponse = response as? HTTPURLResponse, httpResponse.statusCode == 200 {
            // Parse the JSON response to extract the generated summary
            if let responseJson = try JSONSerialization.jsonObject(with: data, options: []) as? [String: Any],
               let choices = responseJson["choices"] as? [[String: Any]],
               let message = choices.first?["message"] as? [String: Any],
               let content = message["content"] as? String {
                return content
            }
        } else {
            print("Unexpected response status code: \((response as? HTTPURLResponse)?.statusCode ?? -1)")
            print("Response body: \(String(data: data, encoding: .utf8) ?? "Unknown response")")
        }
    } catch {
        print("Error during the request or data fetching: \(error.localizedDescription)")
    }

    return nil
}

App.swift

import SwiftUI
import SwiftData

@main
struct CancerDetectorApp: App {
    @StateObject private var vm = AppViewModel()
    
    var sharedModelContainer: ModelContainer = {
        let schema = Schema([
            Product.self,
            ChatMessage.self
        ])
        let modelConfiguration = ModelConfiguration(schema: schema, isStoredInMemoryOnly: false)

        do {
            return try ModelContainer(for: schema, configurations: [modelConfiguration])
        } catch {
            fatalError("Could not create ModelContainer: \(error)")
        }
    }()
    
    var body: some Scene {
        WindowGroup {
            ContentView()
                .environmentObject(vm)
                .modelContainer(sharedModelContainer)
        }
    }
}

解决方案

  1. 清理旧数据库文件
    SQLite提示no such table: ZCHATMESSAGE,说明添加ChatMessage模型后,原有数据库未自动创建对应表。执行以下操作:

    • 在Xcode中选择Product > Clean Build Folder
    • 删除模拟器中的应用,或在真机上卸载应用后重新安装
  2. 验证模型容器配置
    确认App.swift的Schema已正确包含ChatMessage.self,当前代码已满足该要求,无需修改。

  3. 添加查询错误处理
    在ChatView中为@Query添加错误捕获,便于排查后续问题:

    @Query(sort: \ChatMessage.timestamp, order: .forward) private var chatMessages: [ChatMessage]
    @Query private var queryError: Error?
    

    在视图中添加错误显示:

    if let error = queryError {
        Text("Query error: \(error.localizedDescription)")
            .foregroundColor(.red)
            .padding()
    }
    
  4. 确认线程安全
    所有SwiftData操作(插入、保存、查询)均在@MainActor标记的视图中执行,符合主线程要求,当前代码无需调整。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.19 00:00:53