核心数据 - 搜索具有给定标识符的单个对象

Core data - Searches for a single object that has a given identifier

我正在 SwiftUI 中创建一个应用程序,它将成为一本歌集。我想从我有歌曲内容的视图中单击一个按钮,以便 window 出现在我可以输入要切换到的歌曲编号的位置(每首歌曲都有自己的编号) .输入号码后,它应该会带我到该号码的歌曲内容所在的视图。我不太能够从数据库中提取具有给定编号的歌曲并将其显示在视图中。下面我发送我的代码。我指望你的帮助。

核心数据模型:

enter image description here

持久化控制器:

struct PersistenceController {
static let shared = PersistenceController()
let container: NSPersistentContainer

init() {
    container = NSPersistentContainer(name: "Model")
    container.loadPersistentStores { (description, error) in
        if let error = error {
            fatalError("Error \(error.localizedDescription)")
        }
    }
}

func save(completion: @escaping (Error?) -> () = {_ in}) {
    let context = container.viewContext
    if context.hasChanges {
        do {
            try context.save()
            completion(nil)
        } catch {
            completion(error)
        }
    }
}
    
func delete(_ object: NSManagedObject, completion: @escaping (Error?) -> () = {_ in}) {
    let context = container.viewContext
    context.delete(object)
    save(completion: completion)
}

func getSong(number: String) -> Song {
    var song = Song()
    let context = container.viewContext
    let request = NSFetchRequest<NSFetchRequestResult>(entityName: "Song")
    request.predicate = NSCompoundPredicate(format: "number <> '\(number)'")
    
    do {
        song = try context.fetch(request) as? Song ?? Song()
      } catch let error as NSError {
        print("Could not fetch. \(error), \(error.userInfo)")
      }
    return song
}

}

DetailView(我们有歌曲内容的视图):

struct DetailView: View {
@State var isSelected: Bool
    var body: some View {
        VStack{
            Text(song.content ?? "No content")
                .padding()
            Spacer()
        }
        .navigationBarTitle("\(song.number). \(song.title ?? "No title")", displayMode: .inline)
        .toolbar {
            ToolbarItemGroup(placement: .navigationBarTrailing) {
                HStack{
                    Button(action: {
                        song.favorite.toggle()
                        isSelected=song.favorite
                    }) {
                        Image(systemName: "heart.fill")
                            .foregroundColor(isSelected ? .red : .blue)
                }
                
                Button(action: {
                    searchView()
                }) {
                    Image(systemName: "magnifyingglass")
                }
            }
        }
    }
}
func searchView(){
    
    let search = UIAlertController(title: "Go to the song", message: "Enter the number of the song you want to jump to.", preferredStyle: .alert)
    search.addTextField {(number) in
        number.placeholder = "Song number"
    }
    let go = UIAlertAction(title: "Go", style: .default) { (_) in
        let song = PersistenceController.shared.getSong(number: (search.textFields![0].text)!)
        DetailView(song: song, isSelected: song.favorite)
    }
    
    let cancel = UIAlertAction(title: "Cancel", style: .destructive) { (_) in
        print("Cancel")
    }
    search.addAction(cancel)
    search.addAction(go)
    UIApplication.shared.windows.first?.rootViewController?.present(search, animated: true, completion: {
    })
}

}

getSong方法不行,谓词错误,fetchreturn总是一个数组,强烈建议指定实体的静态类型而不是未指定NSFetchRequestResult

并且由于 song 显然是一个 NSManagedObject 子类,您不能使用默认初始化程序 Song() 创建实例。更好的 return 一个可选的

func getSong(number: String) -> Song? {
    guard let songNumber = Int64(number) else { return nil }
    let context = container.viewContext
    let request = NSFetchRequest<Song>(entityName: "Song")
    request.predicate = NSPredicate(format: "number == %ld", songNumber)
    
    do {
        return try context.fetch(request).first
    } catch {
        print(error)
        return nil
    }
}