In my project I have some objects that I show from a server, lets call them Foo's. When I get my Foo feed, I parse them into a NSMutableDictionary subclass called RemoteFoo, and pass these RemoteFoo objects all around the app to display data.
If the user ends up wanting to download a RemoteFoo, I then create a core-data NSManagedObject entity called Foo, and instantiate it using the values from the RemoteFoo. All this works.
The problem I have is that If I want a method to run on a RemoteFoo and a Foo, I have to duplicate it in both RemoteFoo.m and Foo.m. Also, my app if full of duplicate init's like:
- (id)initWithFoo:(Foo *)foo;
- (id)initWithRemoteFoo:(RemoteFoo *)foo;
How can I avoid all of this code-duplication while still separating the temporary remote RemoteFoo from the core-data Foo entities that represent the Foo the user has saved locally?
Have you thought of using something like a class cluster -
http://seanmurph.com/weblog/make-your-own-abstract-factory-class-cluster-in-objective-c/
--------- Foo -------- NSManagedObject
| | |
RemoteFoo LocalFoo ------ CoreDataFoo
You could just save all RemoteFoo's as Foo's and work with those. If you need different behavior, you could have an attribute on Foo indicating if it's remote or not.
Change your Core Data model as follow. Use one Foo instance and add a boolean attribute isRemote (or something similar) that you set by default to NO. When you download your remote objects, instantiate those as Foo managed objects and set their isRemote attribute to yes.
This way, you only need to deal with one instance in your app, while retaining the ability to clearly differentiate between local and remote Foo objects. If your app allows this you may even declare the isRemote attribute as transient, so that it will never be stored on disk, just in memory. If you do no care to persist this information, then this may be the best way to go.
Related
This is more of a generalized question as I have yet to write the code for the question I am asking. Before I get started writing the code I wanted to make sure I am on the right track and possibly getting suggestions for better ways to do what I want to do. Basically right now I have a core data model setup in a way that I think is correct for what I am trying to do and just need some guidance on a very specific part of the code but want to make sure overall I created it correctly.
The first part to the question is more of a clarification on how relationships work in core data. Right now I have 5 entities and to make sure I have the correct idea on how it works I will use a few examples to make sure I am on the right track.
So lets save I have an entity I called name. Within that Name entity that contains only a name attribute. Next I have an entity that has classes, that each have a boolean of true or false to determine which class it is. These 2 are related in a inverse relationship of Name entity having a to one relationship and the Classes having a to many relationship because multiple names can have multiple classes but each name can only have 1 class. If I am right on this one that means I full understand core data relationships!
Now the second part of the question is related to the booleans in the class. I have the Class entity which is like I said a boolean containing a true false set as default to false. When the user selects one of the class buttons before presenting the popover where they actually give the name of the class selected it saves the boolean to true then passes that data over to the popover Name view controller. I am very unsure as to how to do this as it isn't a widely asked question on here nor have I been able to find any info through researching. I am one of those people who needs to actually learn by clear examples....any help with this would be appreciated! Sorry I don't have any example code for this.
The first part seems correct. The ManagedObject of your Class CoreDataObject should have an NSSet property which will contain the names (as the Class can have multiple names)
For the second part, Core Data uses objects. When you 'get' the data from Core Data it will be a (probably extended) NSManagedObject (named Class in our case). You can send this object as a parameter just as you would do with any other object and use it as you would use any other object :-). For example looping over de NSSet Names
func iterateOverNames(someClass: Class) {
for name: Name in someClass.names {
// do stuff
}
}
You can check these links for more information:
https://realm.io/news/jesse-squires-core-data-swift/
https://developer.apple.com/library/ios/documentation/Cocoa/Reference/CoreDataFramework/Classes/NSManagedObject_Class/index.html
I have splitted my application into two main areas.
Part(A)
PartStashContainer(B)
The content of A should be set based on what user wants.
So basically i can have 1..N classes which could be used in Class URI of Part in application model.
I don't know if i should replace the whole Part(A) with new dynamically created Part(C) which has content i want, or i should somehow to modify the existing Part (call setContributionURI, or setObject methods on Part object?).
It does make more sense to me to modify the existing Part, because it is defined in Application model and therefore already describing the location where the content should be.
Possible solutions:
Modify the Part object so it "reload" its content based on new setup (But how? Can setContributionURI or setObject methods help?)
Remove the old Part and add dynamically on same place in Application model the new Part (using EModelService and EPartService).
other solution??
If you want to reuse the Part then do something like:
MPart part = find or inject your part
MyClass myClass = (MyClass)part.getObject();
... call a method of MyClass to change the contents
MyClass is the class you specify for the object in the application model. You should add a method to that to let you change the contents.
Don't try to call setObject, this is really only for use by Eclipse. I don't think setContributionURI would do anything after the part is created (but I am not sure).
If you want to use different classes for the different data then you really should use different Parts.
I have a class that is used to store and retrieve image data from a cache using NSFileManager. When an instance of it is created, I want to check whether the image directory already exists, and if not, create it. Where is the most appropriate place to put this code? Is this something one would override the designated initializer for?
Thanks for reading.
The initialiser (init) function would be the best place to do it from a programming perspective because the rest of the instance methods would probably rely on having access to the directory to store/retrieve images.
You'd also want any instances created to know whether the accessing/creating was successful so in your initialiser you may wish to put some error handling which returns a nil instance (or throws an exception) if it can't be accessed which can then be handled by the classes which use the instance of your cache class.
I am creating a plist controller class that dose things like takes my plist saves it to the document root saves all the values in my plist to variables that will be used for checking my connection responses.
also I do things like saving new values when needed.
the issue I am having however is that I want to access this one class from many classes but if I initialize it in one class and then another I am creating two objects am I not?
so my question is whats the best way for handling a class that has to be accessed from a couple of different classes?
Where are you using these other classes? If they are view controllers then creating an instance in each is perfectly fine.
If they are objects created within the same view controller, try having your objects take your object as function input. That way you can create one instance of that object and share it with all your other objects. Here is an example:
-(void)myFunction:(plistControlClass *)myPlistController{
}
NSManagedObject *entryObj = [self.fetchedResultsController
objectAtIndexPath:indexPath];
entryObj consists of four String attributes.
If I NSLog entryObj, I get the information I want. I cannot figure out how to access each of these properties individually. I read a similar post where the solution was to call "entity." I cannot figure out how to use "entity" to access a specific attribute.
Any ideas? References? Tutorials?
Thanks in advance.
Properties on managed objects are KVC/KVO compliant so you can access them via:
[entryObj valueForKey:#"name"]
Alternatively you can generate a custom Core Data class with real properties to access these values. See this documentation for more information. The Xcode core data modelling tool can generate these classes for you. While you have the model open, choose "File->New File" and you should see a "Managed Object Class" item. Choose this and select the entities you wish to generate classes for.
Once you have done this and the core data entities have their class name set appropriately, you just cast the NSManagedObject to an instance of your new class and access its properties, i.e.
MyObject *entryObj = (MyObject *) [self.fetchedResultsController
objectAtIndexPath:indexPath];
NSLog(#"Property is %#", entryObj.whatever);
If you build your NSManaged objects with the designer then you can export model classes. From the xcdatamodel do File/New File then pick CocoaTouch Class/Managed Object Class. Next then Next then tick each of your classes. Leave generate accessors and generate obj-c 2.0 properties ticked and click finished.
Now you can include the generated files in your projects and use dot accessor syntax.
Alternatively use [entryObject valueForKey:#"keyname"]; but I prefer to stick to the dot accessor syntax where possible.
For generating real classes with properties to call from your object model, I highly recommend using mogenerator:
http://github.com/rentzsch/mogenerator
That's the main project, but the easy to download installer is here:
http://rentzsch.github.com/mogenerator/
You also get primitive value accessors for numeric types, for free.