invalid redeclaration in auto code generate NSManagedObject Subclass Swift 3
In Xcode 8.1, before using the auto code generator, you must select the entity in your data model:
Then go to the Data Model Inspector tab:
Under "Codegen" select "Manual/Node"
After that you could create a NSManagedObject
subclass without errors.
Alternatively, if you have already used 'Class Definition', you can go into your existing .xcdatamodeld file and set all current entities to 'Manual/None' under Codegen. Make sure to save your project (File -> Save), delete your existing Derived Data, clean the project, and then build. Resolved it for me without having to re-make my whole model.
SwiftUI FetchRequest Error: 'A fetch request must have an entity'
Try the code from the SwiftUI app project template when Core Data support is checked:
MyApp.swift
import SwiftUI
@main
struct MyApp: App {
let persistenceController = PersistenceController.shared
var body: some Scene {
WindowGroup {
ContentView()
.environment(\.managedObjectContext, persistenceController.container.viewContext)
}
}
}
Persistance.swift
import CoreData
struct PersistenceController {
static let shared = PersistenceController()
static var preview: PersistenceController = {
let result = PersistenceController(inMemory: true)
let viewContext = result.container.viewContext
for _ in 0..<10 {
let newItem = Item(context: viewContext)
newItem.timestamp = Date()
}
do {
try viewContext.save()
} catch {
// Replace this implementation with code to handle the error appropriately.
// fatalError() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
let nsError = error as NSError
fatalError("Unresolved error \(nsError), \(nsError.userInfo)")
}
return result
}()
let container: NSPersistentContainer
init(inMemory: Bool = false) {
container = NSPersistentContainer(name: "MyApp")
if inMemory {
container.persistentStoreDescriptions.first!.url = URL(fileURLWithPath: "/dev/null")
}
container.loadPersistentStores(completionHandler: { (storeDescription, error) in
if let error = error as NSError? {
// Replace this implementation with code to handle the error appropriately.
// fatalError() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
/*
Typical reasons for an error here include:
* The parent directory does not exist, cannot be created, or disallows writing.
* The persistent store is not accessible, due to permissions or data protection when the device is locked.
* The device is out of space.
* The store could not be migrated to the current model version.
Check the error message to determine what the actual problem was.
*/
fatalError("Unresolved error \(error), \(error.userInfo)")
}
})
}
}
Convert request Function to Generic type
According to my comment I recommend to use a protocol with extension for example
protocol Fetchable
{
associatedtype FetchableType: NSManagedObject = Self
static var entityName : String { get }
static var managedObjectContext : NSManagedObjectContext { get }
static func objects(for predicate: NSPredicate?) throws -> [FetchableType]
}
extension Fetchable where Self : NSManagedObject, FetchableType == Self
{
static var entityName : String {
return NSStringFromClass(self).components(separatedBy: ".").last!
}
static var managedObjectContext : NSManagedObjectContext {
return (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
}
static func objects(for predicate: NSPredicate?) throws -> [FetchableType]
{
let request = NSFetchRequest<FetchableType>(entityName: entityName)
request.predicate = predicate
return try managedObjectContext.fetch(request)
}
}
Change (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
to the reference to your managed object context.
Make all NSManagedObject
subclasses adopt Fetchable
. There is no extra code needed in the subclasses.
Now you can get the data with
do {
let predicate = NSPredicate(format: ...
let objects = try MyEntity.objects(for: predicate)
} catch {
print(error)
}
That's all, objects
are [MyEntity]
without any type casting and always non-optional on success.
The protocol is easily extendable by default sorting descriptors, sorting directions etc.
Default implementation of protocol extension in Swift not working
We'll use a more scaled-down example (below) to shed light on what goes wrong here. The key "error", however, is that Case
cannot make use of the default implementation of objectWithId()
for ... where T: NSManagedObject, I: AnyObject
; since type Int
does not conform to the type constraint AnyObject
. The latter is used to represent instances of class types, whereas Int
is a value type.
AnyObject
can represent an instance of any class type.
Any
can represent an instance of any type at all, including function types.
From the Language Guide - Type casting.
Subsequently, Case
does not have access to any implementation of the blueprinted objectWithId()
method, and does hence not conform to protocol ObjectByIdFetchable
.
Default extension of Foo
to T
:s conforming to Any
works, since Int
conforms to Any
:
protocol Foo {
typealias T
static func bar()
static func baz()
}
extension Foo where T: Any {
static func bar() { print ("bar") }
}
class Case : Foo {
typealias T = Int
class func baz() {
print("baz")
}
}
The same is, however, not true for extending Foo
to T
:s conforming to AnyObject
, as Int
does not conform to the class-type general AnyObject
:
protocol Foo {
typealias T
static func bar()
static func baz()
}
/* This will not be usable by Case below */
extension Foo where T: AnyObject {
static func bar() { print ("bar") }
}
/* Hence, Case does not conform to Foo, as it contains no
implementation for the blueprinted method bar() */
class Case : Foo {
typealias T = Int
class func baz() {
print("baz")
}
}
Edit addition: note that if you change (as you've posted in you own answer)
typealias T = Int
into
typealias T = NSNumber
then naturally Case
has access to the default implementation of objectWithId()
for ... where T: NSManagedObject, I: AnyObject
, as NSNumber
is class type, which conforms to AnyObject
.
Finally, note from the examples above that the keyword override
is not needed for implementing methods blueprinted in a protocol (e.g., entityName()
method in your example above). The extension of Case
is an protocol extension (conforming to ObjectByIdFetchable
by implementing blueprinted types and methods), and not really comparable to subclassing Case
by a superclass (in which case you might want to override superclass methods).
SwiftUI @FetchRequest crashes the app and returns error
In the @enviromentVAr, sometimes, you need to set the enviroment by yourself.
let managedObjectContext: NSManagedObjectContext = ((UIApplication.shared.delegate as? AppDelegate)?.persistentContainer.viewContext)!
ContentView().environment(\.managedObjectContext, managedObjectContext)
Then the managedObjectContext can work.
@Environment(\.managedObjectContext) var managedObjectContext
Why is executeFetchRequest not returning subclass objects when run under XCTest using Swift?
I had a similar question. Making my entity class public solves the issue and I get the right class type.(CoreData class miss match in unit test)
Xcode 8 generates broken NSManagedObject subclasses for iOS 10
I finally got mine to work. Here is what I did. (Flights is one of my entities)
I setup the xcdatamodeld as follows
And then the entity as
Then I used Editor -> Create NSManagedObject Subclass
This creates two files for my flights entity
Flights+CoreDataProperties.swift
Flights+CoreDataClass.swift
I renamed Flights+CoreDataClass.swift to Flights.swift
Flights.swift is just
import Foundation
import CoreData
@objc(Flights)
public class Flights: NSManagedObject {
}
Flights+CoreDataProperties.swift is
import Foundation
import CoreData
extension Flights {
@nonobjc public class func fetchRequest() -> NSFetchRequest<Flights> {
return NSFetchRequest<Flights>(entityName: "Flights");
}
@NSManaged public var ...
}
This appears to work for me.I could not get Codegen to work in any other way, even though I tried many of the suggestions that were out there.
Also this had me scratching my head for a while and I add it as an assist. Don't forget with the new Generics version of the FetchRequest you can do this
let fetchRequest: NSFetchRequest<NSFetchRequestResult> = NSFetchRequest(entityName: "Flights")
Difficulty figuring out how to fetch an NSManagedObject subclass entity from CoreData
Just to give you a code sample to compere to, without exactly explaining all the places that are wrong, and obviously i can't test this so some things may still be problematic...:
let targetValue = "CrawlerDistance"
let request = NSFetchRequest<CrawlerOne>(entityName: "CrawlerOne")
request.predicate = Predicate(format: "crawlerDistance = %@" , targetValue)
let appDel:AppDelegate = (UIApplication.shared().delegate as! AppDelegate)
let context:NSManagedObjectContext = appDel.managedObjectContext
var results:NSArray = try context.executeFetchRequest(request)
What is the reason for having function for fetchRequest on an NSManagedObject class
It is a convenience factory method to be able to create a fetch request type safe with
let request : NSFetchRequest<Sensor> = Sensor.fetchRequest()
along the lines of the convenience initializer syntax
let sensor = Sensor(context: context)
It's not required.
Related Topics
How to Hide the Navigationbar When Embedding Swiftui in Uikit
How to Check Object Is Nil or Not in Swift
How to Get All Days in Current Week in Swift
Add Custom Header to Collection View Swift
(Swift) Nstimer Stop When Scrolling
How to Use Dispatch Groups to Wait to Call Multiple Functions That Depend on Different Data
Understanding the Removerange(_:) Documentation
Animate the Fractioncomplete of Uiviewpropertyanimator for Blurring the Background
Swift String VS. String! VS. String
Using Guard with a Non-Optional Value Assignment
Insertion-Order Dictionary (Like Java's Linkedhashmap) in Swift
Reading an Inputstream into a Data Object
Get Larger Facebook Image Through Firebase Login