10

Any help appreciated.

Xcode auto updated to 8... I am Targeting IOS 9.3

Have all of the code converted across but one thing is now breaking, I have tried various suggestions in similar questions! My fetch request that was previously working is now breaking.

My goal is to get a distinct list. The app crashes on the line:

let results = try context.fetch(fetchRequest) 

With the error described in the console as:

Could not cast value of type 'NSKnownKeysDictionary1' (0x10fd29328) to 'MyApp.BodyType' (0x10eebc820).

Here is the function

func getBodyTypes() {
            let context = ad.managedObjectContext
            let fetchRequest = NSFetchRequest<BodyType>(entityName: "BodyType")
            fetchRequest.propertiesToFetch = ["name"]
            fetchRequest.returnsDistinctResults = true
            fetchRequest.resultType = NSFetchRequestResultType.dictionaryResultType

            do {
                let results = try context.fetch(fetchRequest)

                for r in results {
                    bodyTypes.append(r.value(forKey: "name") as! String)
                }
            } catch let err as NSError {
                print(err.debugDescription)
            }
}

If the line below is hidden it doesn't break, but then i don't get what i want!

fetchRequest.resultType = NSFetchRequestResultType.dictionaryResultType 

I understand i could use all of the results (4300) and loop through them as a bandaid fix, but this doesn't feel like the correct way to fix this, especially as it was working before!

MyName
  • 101
  • 1
  • 5
  • the same problem. Did you solve it? – Bartłomiej Semańczyk Nov 02 '16 at 08:19
  • Same here :/ Any news? I also temporarily solved it by iterating through the non-distinct results and ignoring duplicates. – dy_ Nov 04 '16 at 10:33
  • Same issue...i am going to do what @datayeah is doing for time being, but otherwise cannot find any solution to this from SQL side yet. – Uzumaki Naruto Dec 27 '16 at 14:58
  • My solution below is the fix for this issue. No need to iterate through non-distinct results. Instead, use the general type `NSFetchRequestResult` when setting up your fetch request; then cast the resulting dictionary to the correct data types. – leanne Jun 20 '17 at 17:09

2 Answers2

16

The trick is to make the generic more general - instead of <BodyType> in your fetch request, use <NSFetchRequestResult>:

let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: "BodyType")

The result of this fetch request is [Any], so you will need to cast to the appropriate dictionary type before using. Eg:

func getBodyTypes() {
    let context = ad.managedObjectContext
    // 1) use the more general type, NSFetchRequestResult, here:
    let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: "BodyType")
    fetchRequest.propertiesToFetch = ["name"]
    fetchRequest.returnsDistinctResults = true
    fetchRequest.resultType = NSFetchRequestResultType.dictionaryResultType

    do {
        let results = try context.fetch(fetchRequest)

        // 2) cast the results to the expected dictionary type:
        let resultsDict = results as! [[String: String]]

        for r in resultsDict {
            bodyTypes.append(r["name"])
        }

    } catch let err as NSError {
        print(err.debugDescription)
    }
}

Note: NSFetchRequestResult is a protocol, adopted by four types:
- NSDictionary,
- NSManagedObject,
- NSManagedObjectID, and
- NSNumber

Typically, we're using it with an NSManagedObject, such as your BodyType. In this case, though, you're getting the dictionary type because of the statement:

fetchRequest.resultType = NSFetchRequestResultType.dictionaryResultType
leanne
  • 7,940
  • 48
  • 77
  • I'm facing the same problem of `.resultDistinctResults`not be taken into account but I'm using a`FetchResultController`to do the fetching, not to do all this setting with results. Could you please have a look at my code an see if you spot what's wrong in there? this is my question: https://stackoverflow.com/questions/56168119/removing-duplicate-objects-from-fetch-based-on-object-parameter-swift Thank you very much – Vincenzo May 17 '19 at 14:15
  • @vincenzo, I looked at your question. It's not actually the same, as it doesn't have to do with casting errors, but rather non-destinct results. I'll taker a deeper dive, still, to see if I can find the issue. I'll answer there, as applicable, since it doesn't apply here... – leanne May 17 '19 at 22:36
  • thank you very much. just a hint as I'm diving into the problem, I'm turning to use normal fetch and result as dictionary. it actually works as I want as far as I don't use mixed properties type to fetch, as soon as use date as well it returns to be non-distinct results..maybe there's a clue there .. – Vincenzo May 17 '19 at 23:05
  • 1
    I've updated my question with newer code as I found what didn't make the fetch returning distinct results. I wasn't passing `.propertiesToGroupBy` and `.propertiesToFetch` propels. It now works. I just have a one little last issue in using the fetch as data source for my `Tableview`. It'd be great if you could still have a look at it. Thank you very much again. – Vincenzo May 18 '19 at 11:44
  • 1
    I found out what my last problem was. As I was using a `FetchResultsController`to perform the fetch I had to set it's type as dictionary as well. Thank you very for taking interest in my issue. – Vincenzo May 19 '19 at 08:51
0

I've outlined a simple step by step approach for Swift 5.x in this answer: https://stackoverflow.com/a/60101960/171933

Johannes Fahrenkrug
  • 42,912
  • 19
  • 126
  • 165