task details:
I'm developing an app that communicates with 1-30 hardware devices simultaneously, each device has it's own tcp connection.
Therefore I created an entity "hardwareObject" which shall represent some properties of that device, e.g. value1 and value2.
I created a connection handler class which I defined as a transient attribute of my "hardwareObject" entity. On UI changes the core data object is modified and the core data object itself tells it's connection to send changes of value1 or value2.
I want to inform an instance of "hardwareObject" when new data arrived via a delegate method, therefore it's a delegate of it's attribute.
I'm wondering if making a NSManagedObject a delegate of s.th. is a good practice?
Might that cause any problems regarding faulting or other core data related things?
Or should I better create a sharedInstance master connection handler object which takes care of each of the connection handlers and talk to my core data objects only on demand?
That's a totally valid design. NSManagedObjects may be managed by their (managed object) context, but if you retain an NSManagedObject it will remain valid, and you're free to implement any special business logic in that class or make it a delegate. In fact, one of the resounds that Core Data allows you to subclass NSManagedObject is such that you can do these things.
Just make sure to unregister your class as the delegate if you need to delete the object from the context.
It sounds like a bad idea. Delegates need to exist for at least as long as the object they are a delegate for, and you don't have control over the lifecycle of managed objects - this is taken care of by the context.
As you mention in your question, faulting could also be an issue - any state information could disappear at any point, again, out of your control.
In addition, this sounds like quite a serious violation of MVC, if that concerns you.
Related
I just started working with core data in iOS app dev using swift. The first two things that I encountered are: 1. AppDelegate 2. NSManagedObjectContext.
I understand that 'AppDelegate.swift' file is a source file just like the 'ViewController.swift'. But in all the tutorials it was referred as 'something which will be used later'. Perhaps, now is the time to get familiar with it. Could you kindly tell me what exactly it does?
What does an object of type 'NSManagedObjectContext' do? What is its function? Could you please put its function in simpler words?
Thanks in advance.
Have a look at the following figure for visual understanding of Key objects in an iOS app:
Role of AppDelegate:
The app delegate is the heart of your app code. It handles app initialization, state transitions, and many high-level app events. This object is also the only one guaranteed to be present in every app, so it is often used to set up the app’s initial data structures.
AppDelegate is used for the whole app, you can use it to manage the app life cycle, on the other hand, ViewController is used for a single view. you can use it to manage life cycle of a view. One app can have multiple views. but only one AppDelegate.
Role of NSManagedObjectContext:
The NSManagedObjectContext is a fundamental concept of Core Data.It is like transaction in a relational data. You can fetch objects, you can create objects , update and delete them, save them back to the persistent store, etc. Basically for all the core data operations, you will need to interact with NSManagedObjectContext.
UIApplicationDelegate is an interface between device (the iOS system) and your application. You will i.e. handle push notifications in this class
Context is more complicated. Generally all object that comes from CoreData has some context which is responsible for sync all object in this context. So if you fetch object A and in some other point of code you will fetch again this object (lets call it A2) and both are fetched in the same context then A == A2 is always true. But that's just the tip of the iceberg.
This is tagged with iOS, but I'm sure it could be useful for the other Parse SDKs as well. As you may know, Parse added the ability to create native PFObject subclasses to the iOS SDK not too long ago. This is a great addition for a number of reasons. Firstly, it allows compiler to check your code by creating dynamic properties for object attributes:
myObject[#"myAttribute"] is converted to myObject.myAttribute
Secondly, and more important to this question, custom subclasses can have added functionality. For example, say I have created an alarm app that stores Alarm objects on the Parse cloud. In my custom subclass, I can override the + (instancetype)object, - (void)saveEventually, and - (void)deleteEventually methods so that the alarm object can schedule/update/remove a UILocalNotification for itself upon creation, modification, or deletion.
Here's where things get complicated and my actual question comes in. Say a user creates an alarm on one device (which uploads it to the cloud), and then syncs it automatically to another device. The second device obviously updates it's contents in the background with PFQuery's - (BFTask *)findObjectsInBackground and then calls - (BFTask *)fetchIfNecessaryInBackground on each object to ensure that all of its substance is on the device. My question is: What method(s), if any, gets called when a PFObject subclass is found/fetched from the Parse cloud database? For that matter, what about objects initialized from the local datastore?
Like I mentioned, overriding various methods works perfectly for objects that are created and managed on the device, but I am baffled as to how one would run custom code from within a new object that just arrived in memory from the local or remote datastore. Any thoughts or suggestions on how to handle this would be much appreciated. The Parse documentation does not cover such a case, so it may not even be best practice, but it seems to me that it should be. Anyway, thank you for your time and your insights.
As for most subclasses of NSObject, the way to go is probably to override the -init method.
However, as you mentioned in your last paragraph, such practice is undocumented and you should probably avoid it. The way PFObjects work makes it possible to have multiple instances of the same object in memory (multiple PFObjects with the same objectId). And you do not control when or why these objects are created, so relying on code executed when they are initialized is probably a bad idea. If you have been using Core Data, note that Parse really handles things in a different way, so the best practices are different.
For example, I'm not saying this is the case, but what if a copy of each object is created before it is saved ? Of what if the object is created twice when making a query with the 'cache then network' policy ? Even if you make it work, you would still end up with something that could break with every update of the Framework.
I think you should bundle you initialization code in a method of your own that you would call yourself on objects when you receive them from a query or from the local datastore. Overriding is a good design and practice in object oriented programming, but there are some exceptions and I think this is one of them.
I have an NSManagedObject subclass to represent a person on Flickr. I have to grab all the properties to be stored in Core Data of the internet with a URL request. I want to put the functions to grab the data off the web in the Person class. However, the request will be done asynchronously, and the properties will be set on the object in a completion block. Will this cause an error because Core Data is not thread safe?Would it be best to have a seperate class for loading, or would the NSManagedObject Subclass work?
I would put it in a separate class. Not so much for the different threads issue (which is relatively simple to solve by using NSManagedObjectContext's performBlock: method), but for your separation of concerns. The data model should just store the data. It shouldn't have to worry about downloading it. Create a class that downloads the data, and then pass raw data to the NSManagedObject subclass (a method named +objectFromDownloadedData:(NSData *) comes to mind) to create an actual data object that your app can work with.
You could put networking code in an NSManagedObject subclass.
It would be spectacularly poor design to do so, however. Putting networking code in a model class is just terrible app architecture. It could work, but it will be some of the ugliest, most awful code ever seen on iOS.
I have a navigation based application using Core Data and several levels of drill-down navigation. At the last level of the navigation I add records to the managed object store.At each level of navigation I create an array of view controllers for the next UITableView.
My question concerns the placement of the Core Data stack methods which create the managedObjectContext, managedObjectModel and the persistentStoreCoordinator.
Do I create these methods in the highest level view controller that needs to fetch data from the persistentStore and then pass a context object to the lower level viewcontrollers? Do I also need to pass a coordinator?
Many questions seem to point to putting these methods in the App Delegate but then many answers say "Do Not" put them in the app delegate. So where is the best place for these methods and which objects need to be passed to allow all necessary levels to fetch from the data store?
First, some pre-requisites:
If you're building an application that uses Core Data, then you will most probably encounter situations where you will need to have more than one managed object context (MOC) around. You will however need one MOC that will "live" throughout the whole application session. Call that your main MOC (since you'll be accessing it from the main thread only!!).
More rarely and depending on your application, you may also encounter situations where you will need more than one NSPersistentStoreCoordinator. In my answer I will stick to the case where a single coordinator is required. As for your NSManagedObjectModel, that is entirely dependent on your application. Usually, you only need one of those.
To answer your questions:
I suggest having your main MOC be owned by the AppDelegate, since the latter is a singleton that lives for as long as the application lives. You can put the methods for creating/saving the main MOC in the AppDelegate, or delegate these tasks to a utility class. I find the second option a little cleaner, as you can use that utility class to add methods that create other MOCs on the fly, or to get a reference to the main MOC, from any controller in your application. That way, you avoid calling the AppDelegate all the time.
Note also, that if you already have a NSManagedObject in your hands, you can get the reference to the MOC that it's registered with, simply by calling [yourManagedObject managedObjectContext]. Once you have the MOC reference, you can get the associated NSPersistentStoreCoordinator and NSManagedObjectModel references. (This is to answer your question about "passing the coordinator": I prefer working with NSManagedObjects and the NSManagedObjectContext since they are at the top-most level of the abstraction, instead of passing around the coordinator or the model).
Hope this helps!
Apple puts the Core Data stack in the app delegate which works for the majority of cases.
It sounds to me like you are under utilizing Core Data. It sounds like your app design just uses Core Data to persist some data after you've gone down a hierarchy of views that are populated by arrays. Although you can get this work, you lose a lot of the automatic functionality of Core Data.
Core Data is not primarily about saving data. Instead it is an API for creating the model layer in a Model-View-Controller design app. As such, Core Data usually comprises the actual logical "guts" of the application. Apple puts the stack in the app delegate because it is assumed that Core Data will be used throughout the app.
In the standard design, you would use Core Data to populate all your views so you would need Core Data at the top an bottom of any hierarchy.
I wonder when I should use Core Data and when I just should keep it easy and use delegate variables?
Delegate is a design pattern, CoreData a persistence framework. You are comparing things, that are not compare-able.
Edit
Delegate:
A delegate is an "entry point" where an objects allows you to define some custom action.
It is similair to callbacks in some language or interface in Java.
Technically a delegate is just a pointer to an object that conforms to a defined protocol
Delegation is a simple and powerful
pattern in which one object in a
program acts on behalf of, or in
coordination with, another object. The
delegating object keeps a reference to
the other object—the delegate—and at
the appropriate time sends a message
to it. The message informs the
delegate of an event that the
delegating object is about to handle
or has just handled. The delegate may
respond to the message by updating the
appearance or state of itself or other
objects in the application, and in
some cases it can return a value that
affects how an impending event is
handled. The main value of delegation
is that it allows you to easily
customize the behavior of several
objects in one central object.
CoreData
CoreData is a Framework for organizing persistence data.
In simplest terms, Core Data is an
object graph that can be persisted to
Disk. [...] Core Data can do a lot
more for us. It serves as the entire
model layer for us. It is not just the
persistence on disk, but it is also
all the objects in memory that we
normally consider to be data objects.
—Marcus Zarra, Core Data