2

I have some functions like this:

func getAllEntities() -> [MyEntity]? {

    let fetchRequest = NSFetchRequest(entityName:"MyEntity")

    var error: NSError?
    let fetchedResults = context.executeFetchRequest(fetchRequest) as! [MyEntity]?

    if let results = fetchedResults {
        return results
    }
    else {
            print("Could not fetch \(error), \(error!.userInfo)")
        }
    }

    return nil
}

And now with the upgrade to Swift 2 and Xcode 7, I get errors like these:

Cannot downcast from '[AnyObject]' to a more optional type '[MyEntity]?'

Call can throw, but it is not marked with 'try' and the error is not handled

This is after having performed the automatic Swift code migration you are asked to do when you first start Xcode 7. What is the correct way to re-write my function in the new Swift version?

Thanks

EDIT: I need to keep backwards compatibility with iOS 7 and iOS 8.

AppsDev
  • 12,319
  • 23
  • 93
  • 186

2 Answers2

2

There are two errors:

  • In Swift 2, executeFetchRequest() returns a non-optional. So you cannot cast the return value to [MyEntity]?. You can (forced or optionally) cast it to [MyEntity].
  • executeFetchRequest() throws an error in the error case, so it must be called with try inside a do-catch statement.

Example:

func getAllEntities() -> [MyEntity]? {

    let fetchRequest = NSFetchRequest(entityName: "MyEntity")
    do {
        let results = try context.executeFetchRequest(fetchRequest) as! [MyEntity]
        return results
    } catch let error as NSError {
        print("Could not fetch \(error), \(error.userInfo)")
        return nil
    }
}

A forced cast as! [MyEntity] is acceptable here (as in your original code) because you know the class for the entity, it is set in the Core Data model inspector.

Martin R
  • 529,903
  • 94
  • 1,240
  • 1,382
  • Thanks. I forgot to mention that I need to keep my app compatible with iOS 7 & 8, and it seems that Swift 2 is only available for iOS 8 and above... I edited my question. How could I handle that? – AppsDev Sep 17 '15 at 07:31
  • @AppsDev: As far as I know, Swift 2 deploys back to iOS 7, so that should not be a problem. – It is *not* possible to write code that compiles with both Swift 1.2 and Swift 2, these version are too different. – Martin R Sep 17 '15 at 07:37
  • Xcode help shows that the new `executeFetchRequest` is available for iOS 8.1 and above – AppsDev Sep 17 '15 at 07:40
  • @AppsDev: executeFetchRequest is available since iOS 3 (see https://developer.apple.com/library/ios/documentation/Cocoa/Reference/CoreDataFramework/Classes/NSManagedObjectContext_Class/#//apple_ref/occ/instm/NSManagedObjectContext/executeFetchRequest:error:). There is no "new" executeFetchRequest, only the mapping to Swift is different between Swift 1.2 and Swift 2. The above code compiles without problems with iOS 7 deployment target in my Xcode 7GM. I will double-check with the final version as soon as I have downloaded it. – Martin R Sep 17 '15 at 07:53
  • @AppsDev: The above code compiles with Xcode 7 and deployment target set to iOS 7.The availability notice in the Xcode help inspector is wrong. – Martin R Sep 17 '15 at 08:32
  • Thanks! I have another question, my project mixes `Objective-C` and `Swift` and now looks like `Swift` code is not accesible from `Objective-C` classes anymore... do you know something about this? – AppsDev Sep 17 '15 at 08:55
  • @AppsDev: That should generally still be possible, so much more information is needed. I would suggest to post a new question with all relevant information. – Btw, the "availability" in the help inspector is wrong even for simple methods like "viewDidLoad". I have posted a question in the Apple Developer Forum: https://forums.developer.apple.com/thread/18318. – Martin R Sep 17 '15 at 09:12
0

For the first error, I usually get suggestions from Xcode, typically asking me to lose the ? or change it to !, I can't offer you a concrete solution.

This is the code to solve the second error:

func getAllEntities() -> [MyEntity]? {

let fetchRequest = NSFetchRequest(entityName:"MyEntity")

var error: NSError?
let fetchedResults = try context.executeFetchRequest(fetchRequest) as! [MyEntity]?

do {
return results
}

catch error {
print("Could not fetch \(error), \(error!.userInfo)")
}

return nil
}
Bright
  • 5,699
  • 2
  • 50
  • 72