What are the functional differences between Coredata's CodeGen 'manual/none + create NSManagedObject subclass' vs. 'category/extension'
To address each of your notes and considering the cases where codegen is set to Manual/None
and Category/Extension
:
- Yes, in either case you can customise the classes however you like (within limits - for example, the class must be a subclass - directly or indirectly - of NSManagedObject).
- Correct. You can add, amend or delete attributes in the model editor. In the
Category/Extension
case, the relevant changes will be made automatically. In theManual/None
case, you can either manually update the Extension (or the class file) or you can redo the "create NSManagedObject subclass" which will update the Extension with the amended attribute details. If you do not do this, Xcode will not recognise the new attribute details and will not provide code completion for them (nor will it successfully compile if you try to override code completion). But unlike what you think this has nothing to do with the properties being marked as@NSManaged
. - Correct. Adding an @NSManaged property to the class definition (or Extension) is enough to tell Xcode that the property exists (so you can reference them in code) but does not create the corresponding getter/setter. So your code will crash.
- Yes, for
Category/Extension
just create and tailor the class file as you require. - Yes, for
Category/Extension
the properties are declared in the automatically created Extension file in Derived Data. - Changing the property definition in any way - from Date to NSDate, or marking it private, or whatever - can only be done in the
Manual/None
case because the Extension file in Derived Data is overwritten with each new build so any changes are lost. - Ditto
- Ditto
- Correct. You could write your app without ever creating separate NSManagedObject subclasses (automatically or manually), if you use KVC to access the properties.
As to your final point: you cannot arbitrarily change the type of the property definition: the type specified in the model editor must correspond to the type specified in the property definition. You can switch between optional and non-optional versions of the same type, and you can switch between Date and NSDate etc, but switching from Date to String will not work. I suspect you are correct that this is due to the bridging between Swift value type and the corresponding Objective-C reference type using as
. See here.
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")
Subclassing NSManagedObject with swift 3 and Xcode 8 beta
It's probably a (beta) clash with the new automatic subclass generation, which can be controlled in the entity inspector of the data model file.
From the documentation (What's New In Core Data)
Xcode automatic subclass generation
Xcode now supports automatic generation of
NSManagedObject
subclasses
in the modeling tool. In the entity inspector:
- Manual/None is the default, and previous behavior; in this case you
should implement your own subclass or useNSManagedObject
.- Category/Extension generates a class extension in a file named like
ClassName+CoreDataGeneratedProperties
. You need to declare/implement
the main class (if in Obj-C, via a header the extension can import
named ClassName.h). -- Class Definition generates subclass files named
likeClassName+CoreDataClass
as well as the files generated for
Category/Extension.
The generated files are placed in DerivedData and
rebuilt on the first build after the model is saved. They are also
indexed by Xcode, so command-clicking on references and fast-opening
by filename works.
NSManagedObject subclass property in category
In previous Xcode releases, only a class was created for each
Core Data entity, e.g. the class "BibleAudio" in BibleAudio.h/.m
. These files were overwritten each time you
re-created the managed object subclasses. Therefore, to add
your own functionality to the Core Data class, you had to define
a category (in separate files) on the class.
The great disadvantage
was that you can add methods in class categories, but not
instance variables. So you could not add a simple property
(backed up by an instance variable). One possible workaround was to
define a transient property in the entity, but this had also
disadvantages.
Now Xcode creates a class "BibleAudio" (in BibleAudio.h/.m
) which is essentially empty,
and a category "BibleAudio (CoreDataProperties)" inBibleAudio + CoreDataProperties.h/.m
The category files contain all the Core Data properties, and are
overwritten when you re-create the managed object subclasses.
The class files BibleAudio.h/.m
are created only once and never overwritten. You can add functionality there: methods as before, but also custom properties and instance variables. Because it is a class
and not a category, the old restrictions don't apply anymore.
Xcode 8 automatic NSManagedObject sublass codegen vs transient properties
I do not think this is possible without generating the NSManagedObject
subclasses.
This is likely what the "Category/Extension"
codegen option helps to address. This codegen option is useful for creating properties (attributes) that you do want Core Data to manage.
Why exactly would one subclass NSManagedObject?
I still don't really get what subclassing NSManagedObject is for - what role does it play?
Convenience for the developer - in terms of CodeSense, shorter syntax, and some compile-time checks that help thwart misspellings of keys.
so what can I do with NSManagedObject? What are the restrictions, must-follow guidelines, and what aren't restrictions?
The UI built into Xcode will make the NSManagedObject subclasses for you - you really don't need to do it by hand - but, basically, they are just NSManagedObject
s with some properties tacked on. Instead of using @synthesize
or such, you use @dynamic
and Apple takes care of the rest for you - hooking up those properties to getters/setters which mimic what you would normally do with a "bare" NSManagedObject
.
I'm trying to make a little box drawing program to learn Core Data, and I'm thinking of adding "draw" methods to a subclass of NSManagedObject so that a view can just tell them to draw for itself - is this permitted?
You could.... but I wouldn't. This sounds like bad design - try to keep your Model and Controllers separate.
Model objects shouldn't contain business logic / drawing code. Use the model simply as the "state" of your application. Make something else responsible for the drawing. Plus, while I can't say this with absolute authority, I believe there is some overhead if you're dealing with updating / retrieving info from an NSManagedObject
.
(Basically, it's like dealing with an NSDictionary
... sorta. It's less efficient to grab items out of a dictionary than it is to access an ivar
.)
For an app that does things like drawing - you'll probably want to avoid that overhead by making a structure for your in-memory things, and possibly a second, similar structure for persistence/serialization (like to CoreData).
So, my question in one sentence would be, what's the "real" difference
between subclassing NSManagedObject and any other class - what does
Core Data do with it?
I would say - don't subclass NSManagedObject by hand at all - use what Xcode gives you. If you want more (other than maybe a custom constructor) then you're probably barking up the wrong tree.
EDIT:
I think there might have been some confusion about what I meant when I said "don't subclass NSManagedObject by hand at all"
To elaborate, and incorporate one of the responses:
Start with the data model designer in Xcode, create your models, and use the following menu option:
Then, you could modify the generated class to include custom:
- Constructors
- Data Conversion Methods
- Validation
- Formatting
- Sort Descriptors
- Filters
If your use case doesn't fit in that list, you should really seriously think about putting it somewhere else (as in your example with the "Draw" method).
All of those things mentioned above could be tacked on to an NSManagedObject subclass which was created for us by Xcode (we didn't create "by hand") - and they all revolve around dealing with the data directly (formats / conversions / etc) and/or around pulling the data out of Core Data (filters / sorting).
They don't add iVars, they don't perform any complicated operations outside of the scope of data storage and retrieval.
Related Topics
How to Manage Swiftui State with Nested Structs
Function That Takes a Protocol and a Conforming Class (!) Instance as Parameters
Difference Between Nsrange and Nsmakerange
Convert Hex-Encoded String to String
Swift Utf8 Encoding and Non Utf8 Character
Why Is Swift's Ternary Operator So Picky About Whitespace
How to Draw a Line Between Two Points in Scenekit
How to Query Nested Data in Firebase Database
When Calling a Function in Swift, What Does Each Part Mean
Swift: How to Reload Row Height in Uitableviewcell Without Reloading Data
Create View Based Nstableview Programmatically Using Bindings in Swift
How Are Int and String Accepted as Anyhashable
Making Parts of Text Bold in Swiftui
Suppressing Implicit Returns in Swift
Get Signed Integer from Swift String of Binary
Swift- Variable Not Initialized Before Use (But It's Not Used)
How to Loop Through an Array from the Second Element in Elegant Way Using Swift