swift - 无法预览此文件,应用程序可能已崩溃 -- 输入特定代码行时发生

标签 swift xcode core-data swiftui

虽然我在堆栈溢出上四处寻找答案,但感觉我的情况对于这个错误来说是独一无二的。

我一直在学习如何在 SwiftUI 中使用 CoreData 来保存持久数据。我首先制作一个基本的电影列表,当您单击“添加电影”按钮时,它会添加带有一些任意文本的电影,重点是让它工作。

我的 ContentView 中有一个列表,它在 Movie 实体上执行 ForEach ,但是在添加这些代码行时:

            List {
                ForEach(movies, id: \.self) { (movie: Movie) in
                    Text(movie.title ?? "Unknown Movie")
                }
            }

我收到错误:

PotentialCrashError: MyMovieList.app may have crashed

MyMovieList.app may have crashed. Check ~/Library/Logs/DiagnosticReports for any crash logs 
from your application.

==================================

|  Error Domain=com.apple.dt.ultraviolet.service Code=12 "Rendering service was interrupted" 
UserInfo={NSLocalizedDescription=Rendering service was interrupted}

但是当我构建并运行该应用程序时,它运行得很好。似乎只有添加特定代码行时预览才会中断。将其注释掉将使预览再次正常工作。

我的Movie实体仅包含属性title,它是一个可选的字符串。

ContentView 的完整代码:

import SwiftUI

struct ContentView: View {
// 1
@FetchRequest(
  // 2
  entity: Movie.entity(),
  // 3
  sortDescriptors: [
    NSSortDescriptor(keyPath: \Movie.title, ascending: true)
  ]
// 4
) var movies: FetchedResults<Movie>

@Environment(\.managedObjectContext) var managedObjectContext

var body: some View {
    NavigationView {
        VStack {
            Button(action: {
                self.addMovie(title: "Generic Movie")
            }) {
                Text("Add Movie")
            }
            List {
                ForEach(movies, id: \.self) { (movie: Movie) in
                    Text(movie.title ?? "Unknown Movie")
                }
            }
        }.navigationBarTitle("My Movies")
    }
}
func deleteItem(at offsets: IndexSet) {
    // 1
    offsets.forEach { index in
      // 2
      let movie = self.movies[index]
      // 3
      self.managedObjectContext.delete(movie)
    }
    // 4
    saveContext()
}
func saveContext() {
    do {
        try managedObjectContext.save()
    } catch {
        print("Error saving managed object context: \(error)")
    }
}
func addMovie(title: String) {
  // 1
  let newMovie = Movie(context: managedObjectContext)

  // 2
  newMovie.title = title

  // 3
  saveContext()
}
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

我的 AppDelegateSceneDelegate 是创建项目时生成的默认值,但无论如何我都会在这里分享它们,因为我知道人们会问。

AppDelegate:

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: "MyMovieList")
    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)")
        }
    }
}

}

SceneDelegate:

import UIKit
import SwiftUI

class SceneDelegate: UIResponder, UIWindowSceneDelegate {

var window: UIWindow?


func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
    // Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`.
    // If using a storyboard, the `window` property will automatically be initialized and attached to the scene.
    // This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead).

    // Get the managed object context from the shared persistent container.
    let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext

    // Create the SwiftUI view and set the context as the value for the managedObjectContext environment keyPath.
    // Add `@Environment(\.managedObjectContext)` in the views that will need the context.
    let contentView = ContentView().environment(\.managedObjectContext, context)

    // Use a UIHostingController as window root view controller.
    if let windowScene = scene as? UIWindowScene {
        let window = UIWindow(windowScene: windowScene)
        window.rootViewController = UIHostingController(rootView: contentView)
        self.window = window
        window.makeKeyAndVisible()
    }
}

func sceneDidDisconnect(_ scene: UIScene) {
    // Called as the scene is being released by the system.
    // This occurs shortly after the scene enters the background, or when its session is discarded.
    // Release any resources associated with this scene that can be re-created the next time the scene connects.
    // The scene may re-connect later, as its session was not neccessarily discarded (see `application:didDiscardSceneSessions` instead).
}

func sceneDidBecomeActive(_ scene: UIScene) {
    // Called when the scene has moved from an inactive state to an active state.
    // Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive.
}

func sceneWillResignActive(_ scene: UIScene) {
    // Called when the scene will move from an active state to an inactive state.
    // This may occur due to temporary interruptions (ex. an incoming phone call).
}

func sceneWillEnterForeground(_ scene: UIScene) {
    // Called as the scene transitions from the background to the foreground.
    // Use this method to undo the changes made on entering the background.
}

func sceneDidEnterBackground(_ scene: UIScene) {
    // Called as the scene transitions from the foreground to the background.
    // Use this method to save data, release shared resources, and store enough scene-specific state information
    // to restore the scene back to its current state.

    // Save changes in the application's managed object context when the application transitions to the background.
    (UIApplication.shared.delegate as? AppDelegate)?.saveContext()
}


}

最佳答案

您需要以与应用程序相同的方式设置预览上下文,因此这是一个解决方案

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        let context = (UIApplication.shared.delegate as! AppDelegate)
              .persistentContainer.viewContext
        return ContentView()
                  .environment(\.managedObjectContext, context)
    }
}

关于swift - 无法预览此文件,应用程序可能已崩溃 -- 输入特定代码行时发生,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62907745/

相关文章:

ios - 加载新 VC 时自动选择文本字段

ios - SwiftUI 文本对齐

iphone - NSManagedObject属性设置为nil返回0

ios - 实体之间的核心数据和 'like' 功能

iphone - 是否可以在获取请求期间让 Core Data 对一对多关系的 "many"部分进行排序?

arrays - 扩展数组的数组 - Swift 4.1

ios - NetworkReachabilityManager 或 Reachability 无法识别在没有互联网的情况下连接 wifi

swift - 项目 'Pods' - 打开整个模块优化

jquery - $.get 在带有 PhoneGap 的 iPhone 模拟器中返回 "[object Document]"

swift - UI 测试包标识符和代码覆盖率