首页 > 解决方案 > 实施核心数据的问题

问题描述

所以繁荣我又回来了另一个可能是愚蠢的问题哈哈。我正在扩展我在 YouTube 教程中找到的直升机游戏作为学习练习。我坚持的部分是我正在尝试使用核心数据来允许用户在他们死时保存他们的分数,并在游戏主屏幕可访问的单独视图中调用这些保存的分数(我正在ContentView使用主屏幕和一个单独GameView的实际游戏)。在我的数据模型中,我定义了一个具有单个属性“名称”的实体“分数”。文件中的核心数据使用GameView没有返回错误,但是当我尝试在要列出分数的视图中获取数据时,出现错误:

“FetchedResults”类型的值没有成员“名称”

下面是代码GameView

    //
//  GameView.swift
//  Helicopter
//
//  Created by Instinct on 10/18/21.
//

import SwiftUI
import AVKit
import CoreData

struct GameView: View{
    @State var audioPlayer: AVAudioPlayer!
    @State private var heliPosition = CGPoint(x:100, y:100)
    @State private var obstPosition = CGPoint(x:1000, y:300)
    @State private var flatObstPosition = CGPoint(x:1000, y: 100)
    @State var timer = Timer.publish(every: 0.2, on: .main, in: .common).autoconnect()
    @State var isPaused = false
    @State private var score = 0
    
    @Environment(\.managedObjectContext) var context
    //    @FetchRequest(entity: Scores.entity(), sortDescriptors: []) var scores: FetchedResults<Scores>
    @State public var newScoreValue = ""
    @State public var selectedScore: Scores?
    
    
    let groundPosition = CGPoint(x: 0, y: 1000)
    func gravity(){
        withAnimation{
            self.heliPosition.y += 50
        }
    }
    func obstMove(){
        if self.obstPosition.x > 0
        {
            withAnimation{
                self.obstPosition.x -= 20
                
            }
        }
        else
        {
            self.obstPosition.x = 1000
            self.obstPosition.y = CGFloat.random(in: 0...500)
        }
    }
    func flatObstMove(){
        if self.flatObstPosition.x > 0
        {
            withAnimation{
                self.flatObstPosition.x -= 20
                
            }
        }
        else
        {
            self.flatObstPosition.x = 1000
            self.flatObstPosition.y = CGFloat.random(in: 0...500)
        }
    }
    func pause(){
        self.timer.upstream.connect().cancel()
        //        self.isPaused = true
    }
    func restart(){
        self.timer = Timer.publish(every: 0.2, on: .main, in: .common).autoconnect()
        self.obstPosition.x = 1000
        self.flatObstPosition.x = 1000
        self.heliPosition = CGPoint(x:100, y:100)
        self.isPaused = false
        self.score = 0
    }
    func resume(){
        self.timer = Timer.publish(every: 0.2, on: .main, in: .common).autoconnect()
        self.obstPosition.x = 1000
        self.flatObstPosition.x = 1000
        self.heliPosition = CGPoint(x:100, y:100)
        self.isPaused = false
    }
    func collisionDetection(){
        
        if abs(heliPosition.x - obstPosition.x) < (25 + 20) && abs(heliPosition.y - obstPosition.y) < (25 + 100){
            pause()
            self.isPaused = true
            //            self.score = 0
        }
        if abs(heliPosition.x - flatObstPosition.x) < (25 + 150) && abs(heliPosition.y - flatObstPosition.y) < (25 + 30){
            pause()
            self.isPaused = true
            //            self.score = 0
        }
    }
    //    func startGame(){
    //        self.timer = Timer.publish(every: 0.2, on: .main, in: .common).autoconnect()
    //        self.obstPosition.x = 1000
    //        self.heliPosition = CGPoint(x:100, y:100)
    //        self.isPaused = false
    //        self.score = 0
    //    }
    func fallOffDetection(){
        if abs(heliPosition.y) > 800{
            pause()
            self.isPaused = true
        }
    }
    func levelDetection(){
        //        if self.isPaused == true{
        //            self.timer.upstream.connect().cancel()
        //        }
        if self.score >= abs(100){
            self.timer = Timer.publish(every: 0.1, on: .main, in: .common).autoconnect()
        }
        else if self.score >= abs(300){
            self.timer = Timer.publish(every: 0.05, on: .main, in: .common).autoconnect()
        }
        else{
            //            Text("Level 1")
            self.timer = Timer.publish(every: 0.2, on: .main, in: .common).autoconnect()
        }
        
    }
    
    func save(scores: Scores?) {
        if self.selectedScore == nil {
            let newScore = Scores(context: self.context)
            newScore.name = newScoreValue
            try? self.context.save()
        }
        //            else {
        //            context.performAndWait {
        //                scores!.name = self.newScoreValue
        //                try? context.save()
        //                self.newScoreValue = ""
        //                self.selectedScore = nil
        //            }
        //        }
    }
    
    
    
    var body: some View {
        
        
        
        GeometryReader{ geo in
            
            ZStack{
                Helicopter()
                    .position(self.heliPosition)
                    .onReceive(self.timer){_ in
                        self.gravity()
                        //                        self.levelDetection()
                    }
                Obstacle()
                    .position(self.obstPosition)
                    .onReceive(timer){_ in
                        //                        withAnimation{
                        self.obstMove()
                        //                        }
                    }
                FlatObstacle()
                    .position(self.flatObstPosition)
                    .onReceive(timer){_ in
                        self.flatObstMove()
                    }
                Ground()
                    .position(self.groundPosition)
                self.isPaused ? HStack {
                    Spacer()
                    Button("restart"){self.restart()}.font(.system(size: 40))
                    Spacer()
                    Button("resume"){self.resume()}.font(.system(size:40))
                    Spacer()
                    Button("save score"){self.save(scores: selectedScore)}
                    
                }: nil
                self.isPaused ? Text("your final score is " + String(self.score)) .position(x: geo.size.width / 2, y: geo.size.height - 700).foregroundColor(Color.white).font(.system(size: 50)): nil
                TextField("\(self.score)", text: $newScoreValue)
                    .foregroundColor(.white)
                    .position(x: geo.size.width - 100, y: geo.size.height / 10)
                    .multilineTextAlignment(.trailing)
                
                
                //                    Spacer()
                Ground()
                    //                        .frame(width: 1000, height: 200)
                    .foregroundColor(Color.blue)
            }
            //            .onAppear {
            //                let sound = Bundle.main.path(forResource: "Calboy - All Night Long_2", ofType: "mp3")
            //                self.audioPlayer = try! AVAudioPlayer( contentsOf: URL(fileURLWithPath: sound!))
            //
            //            }
            
            
            //            }
            
            .frame(width: geo.size.width, height: geo.size.height)
            .background(Color.black)
            .gesture(
                DragGesture()
                    .onChanged{ value in
                        withAnimation{
                            //                        self.heliPosition.x = heliPosition.x
                            self.heliPosition.y = value.location.y
                            
                        }
                        
                    }
                    .onEnded{_ in
                        self.levelDetection()
                    })
            //                TapGesture()
            //                    .onEnded{
            //                        withAnimation{
            //                            self.heliPosition.y -= 100
            //                        }
            //                    })
            //            .onReceive(self.timer){_ in
            //                self.levelDetection()
            //            }
        }
        .onReceive(self.timer) {_ in
            self.collisionDetection()
            self.score += 1
        }
        .onReceive(self.timer){_ in
            self.fallOffDetection()
            //                self.score = 0
        }
        
        
        .edgesIgnoringSafeArea(.all)
        
    }
    
}


struct GameView_Previews: PreviewProvider {
    static var previews: some View {
        GameView()
    }
}

这是分数列表的代码

    //
//  ViewScores.swift
//  Helicopter
//
//  Created by Instinct on 10/19/21.
//

import SwiftUI
import CoreData

struct ScoresList: View{
    @Environment(\.managedObjectContext) var context
    @FetchRequest(entity: Scores.entity(), sortDescriptors: []) var scores: FetchedResults<Scores>
    //    @State public var newScoreValue = ""
    //    @State public var selectedScore: Scores?
    //    @State private var newScoreValue = ""
    //    @State private var selectedScore: Scores?
    //    func load(scores: Scores?) {
    //        if self.selectedScore == nil {
    //            let newScore = Scores(context: self.context)
    //            newScore.name = newScoreValue
    //            try? self.context.()
    //        }
    var body: some View{
        
        List{
            ForEach(scores, id: \.self) { score in
                Text("\(scores.name!)")
                //                    .onTapGesture {
                //                        self.newScore = savedScores.name
                //                        self.selectedScore = savedScores
                //                }
            }
        }
    }
    
}

以防万一,这里是我AppDelegate文件中的代码:

    //
//  AppDelegate.swift
//  CoreDataCRUD
//
//  Created by Krassimir Iankov on 8/7/20.
//  Copyright © 2020 Krassimir Iankov. All rights reserved.
//

import UIKit
import CoreData

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {



    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        // Override point for customization after application launch.
        return true
    }

    // MARK: UISceneSession Lifecycle

    func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration {
        // Called when a new scene session is being created.
        // Use this method to select a configuration to create the new scene with.
        return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role)
    }

    func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set<UISceneSession>) {
        // Called when the user discards a scene session.
        // If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions.
        // Use this method to release any resources that were specific to the discarded scenes, as they will not return.
    }

    // MARK: - Core Data stack

    lazy var persistentContainer: NSPersistentContainer = {
        /*
         The persistent container for the application. This implementation
         creates and returns a container, having loaded the store for the
         application to it. This property is optional since there are legitimate
         error conditions that could cause the creation of the store to fail.
        */
        let container = NSPersistentContainer(name: "Scores")
        container.loadPersistentStores(completionHandler: { (storeDescription, error) in
            if let error = error as NSError? {
                // Replace this implementation with code to handle the error appropriately.
                // fatalError() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
                 
                /*
                 Typical reasons for an error here include:
                 * The parent directory does not exist, cannot be created, or disallows writing.
                 * The persistent store is not accessible, due to permissions or data protection when the device is locked.
                 * The device is out of space.
                 * The store could not be migrated to the current model version.
                 Check the error message to determine what the actual problem was.
                 */
                fatalError("Unresolved error \(error), \(error.userInfo)")
            }
        })
        return container
    }()

    // MARK: - Core Data Saving support

    func saveContext () {
        let context = persistentContainer.viewContext
        if context.hasChanges {
            do {
                try context.save()
            } catch {
                // Replace this implementation with code to handle the error appropriately.
                // fatalError() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
                let nserror = error as NSError
                fatalError("Unresolved error \(nserror), \(nserror.userInfo)")
            }
        }
    }

}

我再次搜索了互联网和文档,但无法弄清楚这一点。任何帮助是极大的赞赏!

标签: iosswiftiphonecore-dataswiftui

解决方案


让您的 Text 使用 ForEach 中的变量

 Text("\(score.name!)")

注意单数,复数是数组。


推荐阅读