CoreData Unrecognized Selector Sent to Instance

I'm trying to add CoreData to my application. This application is going to be a photo application, and give the user the ability to store photos in albums. I have two Entities in CoreData currently, Photo and Album.

The Album entity has four attributes. albumCoverImageData: Binary Data, id: UUID, name: String, passwordProtected: Boolean. In addition to these attributes, it has a relationship photos destination Photo Inverse Album.

The Photo Entity has two attributes, id: UUID and imageData: BinaryData

When trying to add a new album to the database, upon trying to save the context, the application crashes with the following error.

Code Block
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)
libcabi.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

I have attached relevant Files below.





I'm at a loss as to what could be going on here, appreciate any insight!

Edit: It seems like the formatting is strange with the files I posted, so I also have this StackOverflow post where the word limit let me post everything here.

Accepted Reply

and still get the same error.

I cannot reproduce the same error with your updated code.
I guess you have something wrong (which is related to Photo.id) somewhere in the hidden parts of your project.

Can you create a minimized project to reproduce the issue and show whole code of it?


I create 3 albums, open one of the albums to view its content (empty), go back out to the album collection view, and then if I try to add another album

Even if I followed the instruction you have shown, nothing happens. AlbumView is the most suspicious, but not sure. Please show enough code to reproduce the issue.

Replies

Seems this line is critically bad:
Main View
Code Block
                    NSSortDescriptor(keyPath: \Photo.id, ascending: true)

In your Photo, id is a UUID which is NOT comparable. It must be comparable when used in NSSortDescriptor.
(UUID is bridged to NSUUID. NSConcreteUUID in you crash log is one of the private subtypes of NSUUID.)

Please try changing the line to:
Code Block
                    NSSortDescriptor(keyPath: \Photo.id.uuidString, ascending: true)

Or else, you may need to change the type of id to something comparable.
When trying to add that to the line, I receive Thread 1: Fatal error: Could not extract a String from KeyPath Swift.KeyPath<LockIt.Photo, Swift.Optional<Swift.String>>. I originally had just photos in the application, with that NSSortDescriptor and it seemed to work fine before. The issue was introduced when I attempted to add albums to the application.

it seemed to work fine before. The issue was introduced when I attempted to add albums to the application.

The history is not important here.
In your crash log, there is [NSConcreteUUID compare:]: unrecognized selector sent to instance 0x2817b4fe0

The fact in your current project is that iOS runtime tried to send compare: to NSConcreteUUID.
I have added dateAdded to Photo and sorted by the date added, and still get the same error.

Code Block
struct AlbumCollectionView: View {
    @Environment(\.managedObjectContext) var managedObjectContext
    @FetchRequest(entity: Photo.entity(),
                  sortDescriptors: [
                    NSSortDescriptor(keyPath: \Photo.dateAdded, 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)!
        newPhoto.dateAdded = Date()
        print(newPhoto.dateAdded)
        
        saveContext()
    }
    
    func saveContext() {
        do {
            try managedObjectContext.save()
        } catch {
            print("Error saving managed object context: \(error)")
        }
    }
}

This is reliably how I get the issue to happen. I create 3 albums, open one of the albums to view its content (empty), go back out to the album collection view, and then if I try to add another album it crashes with that error.

and still get the same error.

I cannot reproduce the same error with your updated code.
I guess you have something wrong (which is related to Photo.id) somewhere in the hidden parts of your project.

Can you create a minimized project to reproduce the issue and show whole code of it?


I create 3 albums, open one of the albums to view its content (empty), go back out to the album collection view, and then if I try to add another album

Even if I followed the instruction you have shown, nothing happens. AlbumView is the most suspicious, but not sure. Please show enough code to reproduce the issue.
I had to add a dateAdded property and sort by that.
I solved this UUID related crash by extending the sorting key path with ".description" (instead of the earlier suggested but still crashing ".uuidString"):

Code Block
NSSortDescriptor(key: "id.description", ascending: true)