¿Cuáles son las consecuencias negativas, si las hay, de basar una capa de modelo en NSManagedObject?

I've been doing iOS now for about two years and mostly by consequence of simple data layers (no real need for ID's, joins, complex queries, etc), I've always managed persistence manually by extending NSObject, conforming to NSCoder, and saving my data in flat files.

However, now I am in a position where I need to start doing more complex query work and I am digging into CoreData.

My hangup right now is with NSManagedObject. It's a pretty intimidating class and I am wondering if there are any unwritten gotchas I should be aware of that might restrict my freedom while building a sophisticated application.

For example, things like @dynamic getter/setters are not to clear to me, etc

De modo que:

1) Are there any features of NSManagedObject that would prevent me from handling instances of custom classes just as I would with NSObject?

2) Does NSManagedObject have any unusual behavior when objects are handled WITHOUT the presence of a ManagedObjectContext?

3) Can I supplant a @dynamic property declaration with my own custom getter/setter without too much pain? I use a lot of custom setters to enforce business logic.

Y así sucesivamente y así sucesivamente.

Muchas Gracias

preguntado el 08 de noviembre de 11 a las 15:11

3 Respuestas

¡Cuidado!

Core Data is not lightweight. It will require a lot of changes to the way your objects work, unless they are very basic.

1) Are there any features of NSManagedObject that would prevent me from handling instances of custom classes just as I would with NSObject?

Faulting and the lifecycle of managed objects are a little tricky to understand. Your objects can be "faulted" almost at any time (each iteration of the event loop anyway), which makes them lose any non-persistent state. When they get "un-faulted", they don't have access to anything outside the managed object context to restore their state. It's very hard for managed objects to access anything outside the managed object context.

Transient properties are possible, but are pretty much limited to things that can be computed from the persistent properties, since their state will be lost if the object is ever faulted. You also have to formally declare that you're using a transient property in the data model. Trying to just set up instance variables will run into problems.

So basically managed objects properties all must be persistent or related to persistent properties. Look at the objects you're planning to make managed. Are all their instance variables feasible and desirable to put into a persistent store? If not things will not be straightforward. You probably set up your instance variables in your init. There is no init that gets called every time your program runs for managed objects. There are awakeFromInsert and awakeFromFetch, but those don't work exactly like init. Your code calls init and can pass arguments. The framework calls awake and it gets no parameters.

Threading is another issue to consider. A managed object context, and therefore the managed objects in it, are recommended to be used only by a single thread. If you have multiple threads, and they need to access your model, you need to create duplicate managed object contexts containing duplicates of your managed objects. Core Data is designed to handle that without putting too much strain on memory, disk I/O, and processor, but it isn't lightweight from a coding perspective.

2) Does NSManagedObject have any unusual behavior when objects are handled WITHOUT the presence of a ManagedObjectContext?

You cannot have a managed object without a managed object context.

That's not usually an issue. Managed objects carry a pointer to their managed object context. It can be a little limiting though. If something outside your model needs to create a model object as an input to your model, it needs to have access to the managed object context to do that. Hopefully that would be through some kind of abstraction layer so it doesn't need to know it's dealing with Core Data, but you can't just give it a class and have it alloc/init. It is also a bit of work to move managed objects between different managed object contexts.

3) Can I supplant a @dynamic property declaration with my own custom getter/setter without too much pain? I use a lot of custom setters to enforce business logic.

Yes. It's a bit complicated but doable. You write your own accessors. In addition to your business logic, they must call key-value observing methods like willChangeValueForKey:. Then you access the data using primitive accessors.

respondido 09 nov., 11:01

Yeah I do some work from time to time with proxy objects that don't necessarily need to be committed to a DB, seems like Core Data wasn't really designed for that. Even if you can do it, it's not ideal. - M. Ryan

1) Are there any features of NSManagedObject that would prevent me from handling instances of custom classes just as I would with NSObject?

Creating and removing them is different, but not difficult. Otherwise, no

2) Does NSManagedObject have any unusual behavior when objects are handled WITHOUT the presence of a ManagedObjectContext?

I'm not sure what you mean, you can pass a managed object to another class and use it quite happily without the other class knowing about the context, but you deberán have a context somewhere.

3) Can I supplant a @dynamic property declaration with my own custom getter/setter without too much pain? I use a lot of custom setters to enforce business logic.

Yes, NSManagedObject is designed for this purpose. There are plenty of examples of overridden accessors in the core data programming guide - there are some rules you need to follow but they are not too onerous.

Core data is primarily a persistence framework rather than a query framework - I imagine once you get into it you will wonder why you were wasting your time on all those NSCoding implementations...

respondido 08 nov., 11:20

I'm talking about completing an object lifecycle with an NSManagedObject without ever exposing it to persistence, intentionally. Like if I need to create an object in memory temporarily for SOME REASON, needing just an init and release, is that a problem? - M. Ryan

You can't just init, you'd need to create it using the entity description (I think you can pass nil as the context in initWithEntity:insertIntoManagedObjectContext:) but otherwise, you'd be OK. Not sure why you'd want to do that, though... - jrturton

Because I want to create and utilize an object without saving it? That seems pretty common to me. Not every object in a system needs to be exposed to SQLLite, even if it gets deleted subsequently, that seems like such a waste. - M. Ryan

OK, but I'd make sure it was actually causing you a problem before you tried optimising around it. If you don't add it in to your database you won't be able to use it with the queries and so forth you mention in your question. - jrturton

1) Are there any features of NSManagedObject that would prevent me from handling instances of custom classes just as I would with NSObject?

No. You can extend a NSManagedObject subclass just like a NSObject subclass.

2) Does NSManagedObject have any unusual behavior when objects are handled WITHOUT the presence of a ManagedObjectContext?

The @dynamic directive will create accessors optimized for saving in a persistent store managed by a context. The values will still be available just like any other object but you will generate a lot of overhead.

3) Can I supplant a @dynamic property declaration with my own custom getter/setter without too much pain? I use a lot of custom setters to enforce business logic.

You can but you will incur some performance penalty because the generated accessors will be highly optimized for the specific code in your app.

One major point of novice confusion with regard to managed object is missing that the generic NSManagedObject can represent any entity in the data model without subclassing. NSManagedObject has "associative storage" which basically means that it has an open dictionary attached to it that save any key-value pairs. When you you insert a generic NSManagedObject into a context, the keys of the associative storage "dictionary" are set to the property names of the entity given.

Therefore, you are actually never really forced to subclass NSManagedObject. Doing so is largely a matter of convenience.

That is why you sometimes see code that uses generic NSManagedObject and the setValue:forKey and other times you see custom subclasses that use anObject.propertyName.

I would also advise that if you find yourself using or saving managed object outside a context, then chances are good that you have a bad design.

respondido 09 nov., 11:01

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.