Core data iOS 13.4 CoreData SwiftUI应用程序崩溃,出现“0”;EXC_断点(代码=1,子代码=0x1f3751f08)";在设备上

Core data iOS 13.4 CoreData SwiftUI应用程序崩溃,出现“0”;EXC_断点(代码=1,子代码=0x1f3751f08)";在设备上,core-data,swiftui,Core Data,Swiftui,一个非常简单的CoreData应用程序:下面提供了所有代码 启动CoreData模板单视图应用程序 2个分别具有字符串属性的实体:消息(标题)和帖子(名称) 导航视图包含 导航链接到邮件列表 导航链接到帖子列表 每个链接的列表视图(消息/帖子)都有 向列表中添加项目的按钮 从列表中删除所有项目的按钮 现在,当您在模拟器(任何iOS 13.x版本)上运行此应用程序时,所有应用程序都会按照上述说明运行 但在运行iOS 13.4的设备上 点击“消息” 创建/删除消息工作正常,SwiftU

一个非常简单的CoreData应用程序:下面提供了所有代码

  • 启动CoreData模板单视图应用程序
  • 2个分别具有字符串属性的实体:消息(标题)和帖子(名称)
导航视图包含

  • 导航链接到邮件列表
  • 导航链接到帖子列表
每个链接的列表视图(消息/帖子)都有

  • 向列表中添加项目的按钮
  • 从列表中删除所有项目的按钮
现在,当您在模拟器(任何iOS 13.x版本)上运行此应用程序时,所有应用程序都会按照上述说明运行

但在运行iOS 13.4的设备上

  • 点击“消息”
  • 创建/删除消息工作正常,SwiftUi视图会立即更新
  • 点击“后退”
  • 再次点击“消息”。尽管仍然可以创建/删除消息,但仍然可以正常工作:调试器现在显示一条警告:“环境中的上下文未连接到持久存储协调器:NSManagedObjectContext:0x280ed72c0
  • 点击“帖子” ==>应用程序在EXC_断点处崩溃(代码=1,子代码=0x1f3751f08)
您也可以先用POST启动流程,然后在messages列表视图中发生相同的崩溃

我坚信这是一个iOS 13.4错误,因为类似的代码在Xcode 11.3/iOS 13.3上运行良好

有人知道此问题的解决方法吗?

以下是完整项目的链接:

ContentView:

import SwiftUI
import CoreData


struct MessageList: View {
  @Environment(\.managedObjectContext) var moc
  @FetchRequest(entity: Message.entity(), sortDescriptors: [])
  var messages: FetchedResults<Message>

  var body: some View {
    List() {
      ForEach(messages, id: \.self) { message in
        Text(message.title ?? "?")
      }
    }
    .navigationBarItems(trailing:
      HStack(spacing: 16) {
        Button(action: deleteMessages) {
          Image(systemName: "text.badge.minus")
        }
        Button(action: addMessage) {
          Image(systemName: "plus.app")
        }
      }
    )
  }
  func addMessage() {
    let m = Message(context: moc)
    m.title = "Message: \(Date())"
    try! moc.save()
  }
  func deleteMessages() {
    messages.forEach {
      moc.delete($0)
    }
  }
}

struct PostList: View {
  @Environment(\.managedObjectContext) var moc
  @FetchRequest(entity: Post.entity(), sortDescriptors: [])
  var posts: FetchedResults<Post>

  var body: some View {
    List {
      ForEach(0..<posts.count, id: \.self) { post in
        Text(self.posts[post].name ?? "?")
      }
    }
    .navigationBarItems(trailing:
      HStack(spacing: 16) {
        Button(action: deletePosts) {
          Image(systemName: "text.badge.minus")
        }
        Button(action: addPost) {
          Image(systemName: "plus.app")
        }
      }
    )
  }
  func addPost() {
    let p = Post(context: moc)
    p.name = "Post \(UUID().uuidString)"
    try! moc.save()
  }
  func deletePosts() {
    posts.forEach {
      moc.delete($0)
    }
    try! moc.save()
  }
}


struct ContentView: View {
  @Environment(\.managedObjectContext) var moc

  var body: some View {
    NavigationView {
      VStack(alignment: .leading){
        NavigationLink(destination: MessageList()) {
          Text("Messages")
        }.padding()
        NavigationLink(destination: PostList()) {
          Text("Posts")
        }.padding()
        Spacer()
      }
    }.navigationViewStyle(StackNavigationViewStyle())
  }
}

struct ContentView_Previews: PreviewProvider {
  static let moc = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
  static var previews: some View {
    ContentView()
      .environment(\.managedObjectContext, moc)
  }
}
NavigationLink(destination: MessageList().environment(\.managedObjectContext, moc)) {
      Text("Messages")
    }.padding()
NavigationLink(destination: PostList().environment(\.managedObjectContext, moc)) {
      Text("Posts")
    }.padding()
AppDelegate(未更改模板,为完整性而提供):

导入UIKit
导入CoreData
@UIApplicationMain
类AppDelegate:UIResponder、UIApplicationLegate{
func应用程序(application:UIApplication,didFinishLaunchingWithOptions launchOptions:[UIApplication.launchOptions键:任意]?)->Bool{
返回真值
}
func应用程序(uApplication:UIApplication,用于连接的配置SceneSession:UISceneSession,选项:UIScene.ConnectionOptions)->UISceneConfiguration{
返回UISceneConfiguration(名称:“默认配置”,会话角色:ConnectionSceneSession.role)
}
func应用程序(application:UIApplication,DiddDiscardSceneSessions sceneSessions:Set){}
//标记:-核心数据堆栈
lazy var persistentContainer:NSPersistentCloudKitContainer={
let container=NSPersistentCloudKitContainer(名称:“Coredata134”)
中的container.loadPersistentStores(completionHandler:{(storeDescription,错误)
如果let error=错误为N错误{
fatalError(“未解决的错误\(error),\(error.userInfo)”)
}
})
返回容器
}()
func saveContext(){
let context=persistentContainer.viewContext
如果context.has发生更改{
做{
尝试context.save()
}抓住{
设nserror=错误为nserror
fatalError(“未解决的错误\(nserror),\(nserror.userInfo)”)
}
}
}
}
更新iOS 14.0(测试版1):

这个问题似乎已在iOS 14上解决


我也相信这是一个错误

您现在可以通过在ContentView中的NavigationLinks中再次设置环境变量来解决此问题:

import SwiftUI
import CoreData


struct MessageList: View {
  @Environment(\.managedObjectContext) var moc
  @FetchRequest(entity: Message.entity(), sortDescriptors: [])
  var messages: FetchedResults<Message>

  var body: some View {
    List() {
      ForEach(messages, id: \.self) { message in
        Text(message.title ?? "?")
      }
    }
    .navigationBarItems(trailing:
      HStack(spacing: 16) {
        Button(action: deleteMessages) {
          Image(systemName: "text.badge.minus")
        }
        Button(action: addMessage) {
          Image(systemName: "plus.app")
        }
      }
    )
  }
  func addMessage() {
    let m = Message(context: moc)
    m.title = "Message: \(Date())"
    try! moc.save()
  }
  func deleteMessages() {
    messages.forEach {
      moc.delete($0)
    }
  }
}

struct PostList: View {
  @Environment(\.managedObjectContext) var moc
  @FetchRequest(entity: Post.entity(), sortDescriptors: [])
  var posts: FetchedResults<Post>

  var body: some View {
    List {
      ForEach(0..<posts.count, id: \.self) { post in
        Text(self.posts[post].name ?? "?")
      }
    }
    .navigationBarItems(trailing:
      HStack(spacing: 16) {
        Button(action: deletePosts) {
          Image(systemName: "text.badge.minus")
        }
        Button(action: addPost) {
          Image(systemName: "plus.app")
        }
      }
    )
  }
  func addPost() {
    let p = Post(context: moc)
    p.name = "Post \(UUID().uuidString)"
    try! moc.save()
  }
  func deletePosts() {
    posts.forEach {
      moc.delete($0)
    }
    try! moc.save()
  }
}


struct ContentView: View {
  @Environment(\.managedObjectContext) var moc

  var body: some View {
    NavigationView {
      VStack(alignment: .leading){
        NavigationLink(destination: MessageList()) {
          Text("Messages")
        }.padding()
        NavigationLink(destination: PostList()) {
          Text("Posts")
        }.padding()
        Spacer()
      }
    }.navigationViewStyle(StackNavigationViewStyle())
  }
}

struct ContentView_Previews: PreviewProvider {
  static let moc = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
  static var previews: some View {
    ContentView()
      .environment(\.managedObjectContext, moc)
  }
}
NavigationLink(destination: MessageList().environment(\.managedObjectContext, moc)) {
      Text("Messages")
    }.padding()
NavigationLink(destination: PostList().environment(\.managedObjectContext, moc)) {
      Text("Posts")
    }.padding()
编辑:

刚刚注意到,此解决方案至少有一个严重的负面影响:如果目标视图中的@FetchRequest使用sortDescriptor,并且目标视图本身包含一个NavigationLink(例如到DetailView),则修改DetailView中sortDescriptor中包含的属性将导致在新属性值导致新排序顺序时,DetailView将立即弹出并再次推送

为了证明这一点:

a) 向核心数据模型中的消息实体添加一个名为“value”的Integer 16类型的新属性

b) 更新func addMessage(),如下所示:

func addMessage() {
    let m = Message(context: moc)
    m.title = "Message: \(Date())"
    m.value = 0
    try! moc.save()
}
ForEach(messages, id: \.self) { message in
        NavigationLink(destination: MessageDetailList(message: message).environment(\.managedObjectContext, self.moc)) {
            Text("\(message.title ?? "?"): value = \(message.value)")
        }
    }
c) 将以下结构添加到ContentView.swift

struct MessageDetailList: View {
    @ObservedObject var message: Message
    var body: some View {
        Button(action: {
            self.message.value += 1
        }) {
            Text("\(message.title ?? "?"): value = \(message.value)")
        }
    }
}
d) 按如下方式更新结构消息列表中的ForEach:

func addMessage() {
    let m = Message(context: moc)
    m.title = "Message: \(Date())"
    m.value = 0
    try! moc.save()
}
ForEach(messages, id: \.self) { message in
        NavigationLink(destination: MessageDetailList(message: message).environment(\.managedObjectContext, self.moc)) {
            Text("\(message.title ?? "?"): value = \(message.value)")
        }
    }
e) 将MessageList中的@FetchRequest替换为:

@FetchRequest(entity: Message.entity(), sortDescriptors: [NSSortDescriptor(key: "value", ascending: false)])
运行代码并点击“消息”。创建三条消息,然后点击第三条消息。在DetailView中,点击按钮。这会将此消息的value属性增加为1,从而调用MessageList上的fetch results,这将触发弹出并再次推送详细信息列表


谢谢。这是可行的。当苹果决定用一个小版本来改变API行为时,这是非常痛苦的。我似乎也遇到了这个问题。使用上面的例子,当我调用
打印(消息)
时。我不完全确定如何解决这个问题。关于如何利用
环境(\.managedObjectContext,moc)