I am using CoreData in my application. I want to abstract out all the CoreData related stuff as an API so that the consume can use the API instead of directly using CoreData and its generated model objects. CoreData generates the managed objects model as following
#interface Person : NSManagedObject
#end
I want to define my API for example MyAPI and it has a function called as
createPerson:(Person*)p;
So the consumer of this createPerson API needs to create a Person data object (like POJO in java world) and invoke this API. But I cannot create Person object using
Person *p = [Person alloc] init]
because the designated initializer for this Person model created by CoreData does not allow this type of creation.
So should I define corresponding user facing data object may be PersonDO and this API should take that instead to carry the data into the API implementation?
Is my approach right? Any expert advise if design the API this way is a good design pattern?
You can't use CoreData without dealing with Managed Object Context. You MUST get the person from the context and save it in the context. If you don't want your customer to deal with that, and you don't use different threads in your app,you could create a api,that will call your appdelegate's Managed Object Context, and all the user will need to do is just to call that method.
For example,you could use automaticly generated by Core Data methods to make your API like that:
+ (Person *)newPersonWithAttributes:(NSDictionary *)userInfo {
// Call the designated initializer, but customer
// doesn't need to think about managed object context
return [Person initPesonWithAttributes:userInfo
inManagedObjectContext:[[AppDelegate sharedAppDelegate] managedObjectContext]];
}
You need lots of stuff to abstract that out. RestKit provides mechanisms to do that. Lighter weight would be InnerBand (See tutorial InnerBand CoreData) - though it does not automatically determine threads/queues for multi-threads.
However, it is a very simple API, and should give you most of what you want.
Related
I have a class called Contact and one called Account
and I have a method called public static Account GetAccount(Contact c) {...}
Where is the best place to put this method? What design patterns should I be looking at?
A) With the Contact class
B) With the Account class
C) Have the method accessible in both classes
D) Somewhere else?
There are probably many good answers to your question. I'll take a stab at an answer, but it will have my personal biases baked in it.
In OOP, you generally don't see globally accessible) functions, disconnected from, but available to all classes. (Static methods might be globally available, but they are still tied to a particular class). To follow up on dkatzel's answer, a common pattern is in OOP is instance manager. You have a class or instance that provides access to a a database, file store, REST service, or some other place where Contact or Account objects are saved for future use.
You might be using a persistence framework with your Python project. Maybe something like this: https://docs.djangoproject.com/en/dev/topics/db/managers/
Some persistence frameworks create handy methods instance methods like Contact.getAccount() -- send the getAccount message to a contact and the method return the associated Account object. ...Or developers can add these sorts of convenience methods themselves.
Another kind of convenience method can live on the static side of a class. For example, the Account class could have a static getAccountForContact() method that returns a particular account for a given Contact object. This method would access the instance manager and use the information in the contact object to look up the correct account.
Usually you would not add a static method to the Contact class called getAccountForContact(). Instead, you would create an instance method on Contact called getAccount(). This method could then call Account.getAccountForContact() and pass "self" in as the parameter. (Or talk to an instance manager directly).
My guiding principle is typically DRY - do not repeat yourself. I pick the option that eliminates the most copy-and-paste code.
If you define your method in this way, it's not really connected with either of your classes. You can as well put it in a Util class:
public class AccountUtil{
public static Account getAccount(Contact c){ ... }
// you can put other methods here, e.g.
public static Contact getContact(Account a){ ... }
}
This follows the pattern of grouping static functions in utility classes like Math in Java / C#.
If you would like to bound the function to a class in a clear way, consider designing your class like this:
public class Contact{
public Account getAccount(){ ... } // returns the Account of this Contact
// other methods
}
In OOP it is generally recommended that you avoid using global functions when possible. If you want a static function anyways, I'd put it in a separate class.
It depends on how the lookup from Contact to Account happens but I would vote for putting it in a new class that uses the Repository pattern.
Repository repo = ...
Account account = repo.getAccount(contact);
That way you can have multiple Repository implemtations that look up the info from a database, or an HTTP request or internal mapping etc. and you don't have to modify the code that uses the repositories.
My vote is for a new class, especially if the function returns an existing account object. That is, if you have a collection of instances of Contact and a collection of instances of Account and this function maps one to the other, use a new class to encapsulate this mapping.
Otherwise, it probably makes sense as a method on Contact if GetAccount returns a new account filled in from a template. This would hold if GetAccount is something like a factory method for the Account class, or if the Account class is just a record type (instances of which have lifetimes which are bound to instances of Contact).
The only way I see this making sense as part of Account is if it makes sense as a constructor.
I'll first of all point out that i need advice and not code samples here. I know how to do the code...
I'm in a project where i feel the need to refactor a singleton class with (in my opinion) excessive use of delegations.
The state is that there are two classes, a singleton class "Manager" and another class "BackendManager". These two do most of the entire app's client-server communication as well as a some application logic.
The application is built up of a login, a menu, and some different functions. All these functions are completely independent, one could be a google map showing some business locations and another could be a calendar showing which meetings the user has. The only connection between these to functions is the login itself. This tells me for sure i need to take the code in the "Manager" and "BackendManager" classes related to the map and put in one place and the stuff for the calendar and put another place. And the same for all the other functions. Furthermore take the login and menu functionality and put somewhere else.
The thing i'm unsure about is whether or not to keep the delegation pattern for all these methods or replace some of it with notifications. The reason is that it's currently a big mess. The "Manager" has a "ManagerDelegate" protocol. It's obvious that this protocol has just gotten bigger and bigger in time. First it defines some login methods, for example
- (void)loginSuccess;
then it defines some maps functions
- (void)backendManagerDidLoadLocationTypes:(NSArray*)locationTypes;
- (void)backendManagerDidLoadLocations:(NSArray*)locations;
- (void)backendManagerDidLoadUserLocatios:(CLLocation*)location;
- (void)backendManagerDidLoadSearchResults:(NSArray*)results;
...
then some calendar functions
- (void)backendManagerDidLoadEvents:(NSArray*)events
- (void)backendManagerDidLoadEventTypes:(NSArray*)eventTypes
...
this of course goes on for all functions developed for the menu, as mentioned these are all independent of eachother.
You can imagine the "BackendManager" is just a convenience class for doing the actual fetching of data for rest services. It is done so the "BackendManager" roughly defines all the same methods as the "Manager", for example for the login functionality:
*Manager*
-(void)userLogin:(NSString*)username pin:(NSString*)pin
-(void)backendUserLogInSuccesCallBack:(BackendManager *)controller
*BackendManager*
-(void)userLogIn:(NSString*)username pin:(NSString*)pin
//Same for all other functions in both classes
So the "Manager" just calls the "BackendManager" and then the "BackendManager" will callback the "Manager" which will call the actual controller from where the call originated, for example LoginViewController. This makes the "Manager" superflous and just an annoying class to always go though when trying to understand the code.
Anyway, after walking through all this logic heres what i plan to do:
Build a model class for every function in the app.
LoginModel
MenuModel
MapModel
CalendarModel
...
These will all be singletons and i'll probably make a class to help doing the service-calls, but parsing of the response and other logic will be in the Models themselves for now.
So the question is - does this sound like the right approach, and am i right in thinking that it would be correct take the calls from "Manager" to the controllers, which are currently done using delegation and change them to use notification pattern (NSNotificationCenter), the calls corresponding to these would now be done in for example the LoginModel where is would throw a notification when logged in. The LoginViewController would then be listening for this notification.
The change to notifications is mostly based on the MVC model teached in the Stanford lessons, here i interpret that the delegation pattern is mostly used when communicating between Controllers and Views, and notifications of KVO is used when communicating from the Model to the controller.
This means that now, instead of sending userdata back from the "Manager" to the controller like
- (void)backendManagerDidLoadLocationTypes:(NSArray*)locationTypes;
above, I will throw a notification when they have been fetched and the controller will then fetch the locationtypes from the model using a different call. This would give me two calls in the Model, one to "update" the locationTypes (from server) and one to "get" them (locally). So maybe these types of calls are the ones where i should stick to the delegation pattern? Even though i'd rather use delegation only between views and controllers.
First off, this question is more suited for programmers.stackexchange.com, but I'll give you a quick answer here.
I like the approach of using notifications application level events. UserDidLogin and LocationDidChange are good examples. These events signal a change that all view controllers will want to know about.
I would avoid singletons. Usually view controllers can exchange data in -prepareForSegue:sender: or however you create your child view controllers.
As far as notifications for completed network events with update and get methods: I would avoid this. Always ask for the data using some async method (I prefer completion blocks), let the model take care of when to use a cached copy and when to update from the server.
I would also recommend splitting the control of access to model data from the model. People sometimes label this as a manger pattern, a factory pattern, or a data source pattern, but it all amounts to the same thing. Have a separate object which knows how to fetch data for one particle model. That object will return back fully formed model data.
For example, have a locationTypeDataSource object. The view controller requests location type data from this data source. The data source thens tells the view controller when the data is ready. This could be reported as a notification, KVO, or completion block.
Notification:
[self addObserverForName:LocationTypeDidLoad object:self.locationTypeDataSource queue:nil usingBlock:^(NSNotification *note) {
[self.tableView refreshData]; // or whatever
}
[self.locationTypeDataSource fetchLocationTypes];
KVO:
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object
change:(NSDictionary *)change context:(void *)context
{
if ([keyPath isEqualToString:#"locationTypeDataSource.locationTypes"]) {
[self.tableView refreshData]; // or whatever
}
}
[self addObserver:self forKeyPath:#"locationTypeDataSource.locationTypes" options:0 context:NULL];
[self.locationTypeDataSource fetchLocationTypes];
Completion Block:
[self.locationTypesDataSource fetchLocationTypesWithCompletion:^(NSArray *locationTypes, NSError *error){
[self.tableView refreshData]; // or whatever
}];
The key is to use a separate object to fetch and prepare model data.
The Problem
I have a class which calculates the path a user took using CoreLocation and and array of arrays containing the coordinates of each point (taken when the users location changes). This class method is being called by my View Controller, but I want to set it's delegate to another class which will store the result in Core Data or upload it to a database. I can return the array to the View Controller by using:
PathFinder.delegate = self
Then make my View Controller implement my delegate protocol, but this isn't what I want.
What I've Considered
I've thought about making the class which uploads the data to the database/stores it in Core Data a singleton class so that I can easily access it from my View Controller. E.g.
PathFinder.delegate = <MY SINGLETON CLASS>
Conclusion
What would be the best way to do this? Would it be bad practice to put the code to upload the array to my server in the PathFinder class? Any help would be appreciated.
I have something like this - a singleton class that manages a Core Data repository for images (some in the repository, some on the file system but a URL in the entity).
Why not have a singleton class that all objects that need the services import? That way, you tell some object to do something, when that works is done they tell the repository to save it. You can use a delegate protocol to know if it succeeded or not, but just decouple the saving of it from driving the process and knowing the outcome.
I'd like to link my custom domain object into the Petrel free memory command. My domain object caches data while visualised and this cache could be cleared when the user wants to free memory.
I have found the IMemorySaver interface and tried declaring this on my custom domain object but the FreeMemory method is not called when the user choose to free memory in Petrel.
Any ideas?
Neal
In Ocean 2013.1 a new API has been introduced that allows custom domain objects and ToggleWindows from a plug-in to be told when the user has invoked the ‘Free memory’ feature (this will also work for programmatic calls to PetrelSystem.ForceFreeMemory()).
The API follows a similar pattern to the existing INameInfoFactory and IImageInfoFactory APIs.
In order to use the API you need to create a factory object for your custom domain object (or ToggleWindow) that implements the new IResourceSaverFactory interface.
This interface requires that you implement a single method called GetResourceSaver(). This
method will return a ResourceSaver object that is associated with your custom domain object (or ToggleWindow).
ResourceSaver is an abstract class and you should implement the FreeResources() method on your derived class.
When the ‘Free memory’ feature is invoked the system will use your ResourceSaverFactory to obtain a ResourceSaver object for each of your custom domain object (or ToggleWindow) instances.
The FreeResources() method will be called on your ResouceSaver
objects.
Regards,
Chippy
Neal, the IMemorySaver is declared as a service interface, which you should not re-implement.
Having said that, participation in Petrel's controlled resource management is a fair requirement.
I have set up a Core Data model where I have two objects, say Person and Address. A person has an address, and an address can belong to many people. I have modelled it in core data as such (so the double arrow points to Person, while the single arrow goes to Address)
I have then created two classes for those objects, and implemented some custom methods in those classes. In the Core Data model I have entered the names of the classes into them.
If I fetch an Address from Core Data directly, it gives me the actual concrete class and I can call my custom methods on it.
If on the other hand I fetch a Person and try to access the Address through Person (eg: person.address) I get back an NSManagedObject that is an address (eg: I can get to all the core data attributes I've set on it) but it doesn't respond to my custom methods, because it's of type NSManagedObject instead of Address. Is this a limitation of Core Data or am I doing something wrong? If it is a limitation are there any work arounds?
Did you create those classes using the modeller (Select an Entity, File > new file.., Managed Object Class, then select the Model Entity)?
A while ago I had a similar problem because I didn't create my managed object models using the Modeller. What I did to make sure everything was up and running was to copy and save my custom methods (and everything else I'd implemented) and start from scratch using the modeller. Then I was able to customize my model classes again and everything worked just fine.
I know this is not a complete answer but perhaps it can help you until someone explains exactly what is going on.
Cheers!
You probably just forgot to set the name of the class in the model when you created the entity - it defaults to NSManagedObject. Click on Person and Address in the modeller and check, on the far right side where the Entity properties are listed, that the Class field is filled in correctly with the name of the corresponding objective C class and isn't just the default NSManagedObject setting.
Your implementation file for the class probably hasn't been added to the Target that you are running.
(Get Info on the .m file -> Check the targets tab)
If your xcdatamodel has the Class set, if it can't find it at run time it will still work, you will just get NSManagedObject instances back instead. Which will actually work just fine, until you try to add another method to the class, as you have found.