发送到实例的 CoreData 无法识别的选择器

Posted

技术标签:

【中文标题】发送到实例的 CoreData 无法识别的选择器【英文标题】:CoreData Unrecognized Selector Sent to Instance 【发布时间】:2020-10-20 20:07:57 【问题描述】:

我正在尝试将 CoreData 添加到我的应用程序中。这个应用程序将成为一个照片应用程序,并让用户能够将照片存储在相册中。我目前在 CoreData 中有两个实体,PhotoAlbum

Album 实体有四个属性。 albumCoverImageData: Binary Dataid: UUIDname: StringpasswordProtected: Boolean。除了这些属性之外,它还有一个关系photosdestination PhotoInverse Album

Photo 实体有两个属性,id: UUIDimageData: BinaryData

尝试向数据库添加新专辑时,尝试保存上下文时,应用程序崩溃并出现以下错误。

2020-10-20 15:49:33.889808-0400 LockIt[902:92475] -[__NSConcreteUUID compare:]: unrecognized selector sent to instance 0x2817b4fe0

2020-10-20 15:53:28.604954-0400 LockIt[902:92475] [error] error: Serious application error.  Exception was caught during Core Data change processing.  This is usually a bug within an observer of NSManagedObjectContextObjectsDidChangeNotification.  -[__NSConcreteUUID compare:]: unrecognized selector sent to instance 0x2817b4fe0 with userInfo (null)

CoreData: error: Serious application error.  Exception was caught during Core Data change processing.  This is usually a bug within an observer of NSManagedObjectContextObjectsDidChangeNotification.  -[__NSConcreteUUID compare:]: unrecognized selector sent to instance 0x2817b4fe0 with userInfo (null)

2020-10-20 15:53:28.622315-0400 LockIt[902:92475] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSConcreteUUID compare:]: unrecognized selector sent to instance 0x2817b4fe0'

*** First throw call stack:

(0x1937c65ac 0x1a78b442c 0x1936d0a2c 0x1937c9130 0x1937cb420 0x194b18c90 0x1998e5dc8 0x1998e58a0 0x1998e6ad0 0x1998e77b4 0x19989a410 0x199767b64 0x1998e7100 0x193725764 0x193725718 0x193724cd4 0x1937246a0 0x1949bc5f4 0x199892118 0x1998a0c50 0x199892fc0 0x199761aa0 0x104503bd8 0x104502e68 0x104502854 0x199fd2c04 0x19a2c3ec0 0x19a049990 0x19a0499b8 0x19a049990 0x19a03a1dc 0x19a088444 0x19a4d8f58 0x19a4d71a4 0x19a4d7d78 0x195c4d334 0x196177a4c 0x195c43350 0x195c43030 0x19612ef80 0x196108bc0 0x196190118 0x196193070 0x19618a5f4 0x19374381c 0x193743718 0x193742a28 0x19373cd20 0x19373c4bc 0x1aa24e820 0x1960e9164 0x1960ee840 0x1044f2178 0x193403e40)

libc++abi.dylib: terminating with uncaught exception of type NSException

*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSConcreteUUID compare:]: unrecognized selector sent to instance 0x2817b4fe0'

terminating with uncaught exception of type NSException

我在下面附上了相关文件。 照片+CoreDataProperties

import Foundation

import CoreData





extension Photo 



    @nonobjc public class func fetchRequest() -> NSFetchRequest<Photo> 

        return NSFetchRequest<Photo>(entityName: "Photo")

    



    @NSManaged public var id: UUID?

    @NSManaged public var imageData: Data?

    @NSManaged public var album: Album?







extension Photo : Identifiable 



    public var wrappedID: UUID 

        id!

    

    

    public var wrappedImageData: Data 

        imageData!

    


专辑+CoreDataProperties

import Foundation

import CoreData





extension Album 



    @nonobjc public class func fetchRequest() -> NSFetchRequest<Album> 

        return NSFetchRequest<Album>(entityName: "Album")

    



    @NSManaged public var albumCoverImageData: Data?

    @NSManaged public var id: UUID?

    @NSManaged public var name: String?

    @NSManaged public var passwordProtected: Bool

    @NSManaged public var photos: NSSet?

    

    public var wrappedID: UUID 

        id!

    

    

    public var wrappedAlbumCoverImageData: Data 

        albumCoverImageData!

    

    

    public var wrappedName: String 

        name ?? "Unamed Album"

    

    

    public var wrappedPasswordProtected: Bool 

        passwordProtected

    

    

    public var photoArray: [Photo] 

        let set = photos as? Set<Photo> ?? []

        

        return Array(set)

    







// MARK: Generated accessors for photos

extension Album 



    @objc(addPhotosObject:)

    @NSManaged public func addToPhotos(_ value: Photo)



    @objc(removePhotosObject:)

    @NSManaged public func removeFromPhotos(_ value: Photo)



    @objc(addPhotos:)

    @NSManaged public func addToPhotos(_ values: NSSet)



    @objc(removePhotos:)

    @NSManaged public func removeFromPhotos(_ values: NSSet)







extension Album : Identifiable 

    


主视图

import SwiftUI



struct AlbumCollectionView: View 

    @Environment(\.managedObjectContext) var managedObjectContext

    @FetchRequest(entity: Photo.entity(),

                  sortDescriptors: [

                    NSSortDescriptor(keyPath: \Photo.id, ascending: true)

                  ]

    ) var photos: FetchedResults<Photo>

    

    @FetchRequest(entity: Album.entity(),

                  sortDescriptors: [

                    NSSortDescriptor(keyPath: \Album.name, ascending: true)

                  ]

    ) var albums: FetchedResults<Album>

    

    @State private var showingImagePicker = false

    @State private var showingPopover = false

    @State private var inputImage: UIImage?

    @State private var albumNameInput: String = ""

    

    let columns = [

        GridItem(.adaptive(minimum: 150))

    ]

    

    var body: some View 

        ScrollView 

            LazyVGrid(columns: columns, spacing: 20) 

                ForEach(albums)  album in

                    NavigationLink(destination: AlbumView(album: album)) 

                        VStack 

                            Image(data: album.albumCoverImageData, placeholder: "No Image")

                                .resizable()

                                .aspectRatio(1, contentMode: .fill)

                                .contextMenu(menuItems: 

                                    Button(action: 

                                        deleteAlbum(selectedAlbum: album)

                                    ) 

                                        Label("Remove", systemImage: "trash")

                                    

                                )

                            Text(album.name ?? "")

                        

                    

                

            

            .padding()

            .navigationBarTitle(Text("Albums"))

            .navigationBarItems(trailing:

                Menu 

                    Button(action: 

                        self.showingPopover = true

                    ) 

                        Label("Add Album", systemImage: "photo.on.rectangle.angled")

                    

                    Button(action: 

                        self.showingImagePicker = true

                    ) 

                        Label("Add Photo", systemImage: "photo")

                    

                 label: 

                    Image(systemName: "plus")

                        .popover(isPresented: $showingPopover, arrowEdge: .trailing ,content: 

                            VStack 

                                Text("New Album")

                                TextField("Enter Album Name",text: $albumNameInput)

                                    .textFieldStyle(RoundedBorderTextFieldStyle())

                                Button("Submit")

                                    addAlbum(name: albumNameInput, albumCover: UIImage(named: "Image 1")!)

                                    albumNameInput = ""

                                    showingPopover = false

                                

                            

                            .padding()

                        )

                

            )

            .sheet(isPresented: $showingImagePicker, onDismiss: loadImage) 

                ImagePicker(image: self.$inputImage)

            

        

    

    

    func addAlbum(name: String, albumCover: UIImage) 

        let newAlbum = Album(context: managedObjectContext)

        

        newAlbum.id = UUID()

        newAlbum.name = name

        newAlbum.passwordProtected = false

        newAlbum.albumCoverImageData = albumCover.jpegData(compressionQuality: 1.0)

        

        saveContext()

    

    

    func deleteAlbum(selectedAlbum: Album) 

        for album in albums 

            if selectedAlbum == album 

                self.managedObjectContext.delete(album)

            

        

        saveContext()

    

    

    func loadImage() 

        guard let inputImage = inputImage else  return 

        addPhoto(image: inputImage)

    

    

    func addPhoto(image: UIImage) 

        let newPhoto = Photo(context: managedObjectContext)

        

        newPhoto.id = UUID()

        newPhoto.imageData = image.jpegData(compressionQuality: 1.0)

        

        saveContext()

    

    

    func saveContext() 

        do 

            try managedObjectContext.save()

         catch 

            print("Error saving managed object context: \(error)")

        

    


我不知道这里会发生什么,感谢任何见解!

【问题讨论】:

您最近是否在未生成新文件(或手动更新现有文件)的情况下更改了核心数据模型? 我不相信,我可以用它的屏幕截图更新帖子以确保没有差异,但据我所知,我没有也不应该有任何差异。 我们不需要截图,你可以自己检查。我看到了一些类似的问题,这是由更新数据模型引起的,这就是我问的原因。 我没有改过,但我也没有生成新文件。生成文件后,我添加了 wrapped 属性,但这些是我所做的唯一更改。 题外话,但最好将您自己的计算属性和其他内容添加到 单独 文件中的实体类的扩展中 【参考方案1】:

您说添加和保存新的Album 时会出现问题,尽管我认为问题实际上与Photos 有关。错误:

原因:'-[__NSConcreteUUID compare:]:无法识别的选择器发送到实例

使用旧的 Objective-C 术语(CoreData 的核心是基于 Objective-C)。它表明存在__NSConcreteUUID 类型的对象(这可能是CoreData 用来存储UUID 的对象类型)并且CoreData 正在尝试对该对象调用compare 方法。 compare 是在对对象进行排序时调用的方法:将对象 A 与对象 B 进行比较,以确定它们应该相对于彼此放置的顺序。

因此,问题的根源在于您的视图正在按 UUID 对某些内容进行排序,而这似乎是照片:

     @FetchRequest(entity: Photo.entity(),
         sortDescriptors: [
             NSSortDescriptor(keyPath: \Photo.id, ascending: true)
             ]
         ) var photos: FetchedResults<Photo>

但 UUID 不能以这种方式排序。除非有充分的理由按 UUID 排序,否则我只会更改排序顺序以使用不同的属性。

【讨论】:

谢谢!您是否知道可以解释为什么 UUID 不能以这种方式排序的文档,以及哪些键不能用于排序的一般规则是什么?拥有一个具有 UUID 的实体,然后按此 id 排序以保持顺序一致,这感觉很自然。

以上是关于发送到实例的 CoreData 无法识别的选择器的主要内容,如果未能解决你的问题,请参考以下文章

swift coredata - 发送到实例的无法识别的选择器

[AppDelegate managedObjectContext]:发送到实例的无法识别的选择器

核心数据-[Decodable.Address initWithCoder:]:发送到实例的无法识别的选择器

核心数据:发送到实例的无法识别的选择器

NSSortDescriptor 和 [__NSCFNumberlocalizedStandardCompare:]:发送到实例的无法识别的选择器

UITableViewController 无法识别的选择器发送到实例