我主要在 iPad 版 Swift Playgrounds 中创建应用程序,因此我实际上并没有在 XCode 上使用 Core Data 工具。在教程的帮助下,我创建了一个
PersistenceController
和一个数据模型。当我只有一种实体类型 (Club
) 时,一切都运行良好。现在我想要一个不同的、不相关的实体(Game
)。当我尝试在应用程序中的任何位置添加另一个 @FetchRequest
并发送错误“FetchRequest 必须有一个实体”时,我的应用程序崩溃了。我相信这是因为在我的PersistenceController
我有
let model = NSManagedObjectModel()
model.entities = [clubEntity]
//model.entities = [gameEntity]
我认为我需要
model.entities = [gameEntity]’ to fix the error mentioned above, but that will override my clubEntity no? When I include the gameEntity, I get the same error, but it appears on
@main` 而不是在 ContentView 中。我已经包含了我认为可能与该问题相关的所有代码,但我可以根据要求添加更多代码。
import SwiftUI
@main
struct MyApp: App {
@StateObject private var locationManager = LocationManagerModel()
let persistanceController = PersistanceController.shared
var body: some Scene {
WindowGroup {
ContentView()
.environment(\.managedObjectContext, persistanceController.container.viewContext)
.environmentObject(locationManager)
.transition(AnyTransition.opacity.animation(.easeInOut(duration: 0.5)))
}
}
}
import SwiftUI
import CoreData
struct PersistanceController {
static let shared = PersistanceController()
static var preview: PersistanceController = {
let result = PersistanceController(inMemory: true)
let viewContext = result.container.viewContext
// for index in 0..<10 {
//
// }
do {
try viewContext.save()
} catch {
let nsError = error as NSError
fatalError("Unresolved error \(nsError), \(nsError.userInfo)")
}
return result
}()
let container: NSPersistentContainer
init(inMemory: Bool = false) {
let clubEntity = NSEntityDescription()
clubEntity.name = "Club"
clubEntity.managedObjectClassName = "Club"
let idAttribute = NSAttributeDescription()
idAttribute.name = "id"
idAttribute.type = .uuid
clubEntity.properties.append(idAttribute)
let nameAttribute = NSAttributeDescription()
nameAttribute.name = "name"
nameAttribute.type = .string
clubEntity.properties.append(nameAttribute)
let putterAttribute = NSAttributeDescription()
putterAttribute.name = "putter"
putterAttribute.type = .boolean
clubEntity.properties.append(putterAttribute)
let strokesNumAttribute = NSAttributeDescription()
strokesNumAttribute.name = "strokes"
strokesNumAttribute.type = .integer32
clubEntity.properties.append(strokesNumAttribute)
let strokesListAttribute = NSAttributeDescription()
strokesListAttribute.name = "strokesList"
strokesListAttribute.type = .transformable
clubEntity.properties.append(strokesListAttribute)
/////////////////////////////////
let gameEntity = NSEntityDescription()
gameEntity.name = "Game"
gameEntity.managedObjectClassName = "Game"
gameEntity.properties.append(idAttribute)
gameEntity.properties.append(strokesNumAttribute)
let model = NSManagedObjectModel()
model.entities = [clubEntity]
model.entities = [gameEntity]
container = NSPersistentContainer(name: "ClubToDo", managedObjectModel: model)
if inMemory {
container.persistentStoreDescriptions.first!.url = URL(fileURLWithPath: "/dev/null")
}
container.viewContext
.automaticallyMergesChangesFromParent = true
container.loadPersistentStores(completionHandler: {(storeDescription, error) in
if let error = error as NSError? {
fatalError("Unresolved error \(error), \(error.userInfo)")
}
})
}
}
import SwiftUI
import CoreData
import Foundation
@objc(Game)
public class Game: NSManagedObject {
@NSManaged public var id: UUID
@NSManaged public var strokes: Int
}
@objc(Club)
public class Club: NSManagedObject {
@NSManaged public var id: UUID
@NSManaged public var name: String
//@NSManaged public var yardsNum: Int
@NSManaged public var strokes: Int
@NSManaged public var putter: Bool
@NSManaged public var strokesList: [Int]
//@NSManaged public var averageYardage: Int
@NSManaged public var nfcTag: String
}
extension Club: Identifiable {
// var yards: Yards{
// get {
// Yards(rawValue: Int(yardsNum)) ?? .normal
// }
//
// set {
// self.yardsNum = Int(newValue.rawValue)
// }
// }
var strokesStandardDeviation: Double {
guard !strokesList.isEmpty else {
return 0.0 // or another appropriate value when the list is empty
}
let mean = Double(strokesList.reduce(0, +)) / Double(strokesList.count)
let squaredDifferences = strokesList.map { pow(Double($0) - mean, 2) }
let variance = squaredDifferences.reduce(0, +) / Double(strokesList.count)
return sqrt(variance)
}
var averageYardage: Int {
guard !strokesList.isEmpty else {
return 0
}
let numStrokes = strokesList.count
let sumArray = strokesList.reduce(0,+)
let averageYardage = sumArray / numStrokes
return averageYardage
}
}
enum Yards: Int {
case normal = 0
}
import SwiftUI
import CoreLocation
import CoreData
import Combine
struct ContentView: View {
@Environment(\.managedObjectContext) private var viewContext
@FetchRequest(
entity: Club.entity(),
sortDescriptors:[])
private var clubs:FetchedResults<Club>
// @FetchRequest(
// entity: Game.entity(),
// sortDescriptors:[])
// private var games:FetchedResults<Game>
@State private var shotClub = Club()
@State private var ballClub = Club()
@State private var showNewClub: Bool = false
@EnvironmentObject var locationManager: LocationManagerModel
//@State private var game = ""
@AppStorage("NUMBER_KEY") var counter = 0
@State var roundStarted = false
var body: some View {
TabView{
ClubListView(counter: $counter, roundStarted: $roundStarted)
.tabItem {
Image(systemName: "list.bullet.rectangle.portrait")
}
RoundView(counter: $counter, roundStarted: $roundStarted)
.tabItem {
Image(systemName: "flag")
}
}
}
}
model.entities
属性是一个数组,应列出模型中要使用的所有实体。正如您所注意到的,为其分配两次值是行不通的,因为第二次分配会覆盖第一次分配。您需要在一个实体数组中列出单个作业中的所有实体:
model.entities = [clubEntity, gameEntity]
看到如何在代码中设置实体而不使用 Xcode 模型编辑器是非常酷的。没有多少人这样做,而且很多人没有意识到这是可能的。