iOS Should I Use Core Data? [closed] - ios

Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 9 years ago.
Improve this question
I have an exercise application that allows you to create a Workout Program, and then create individual Workouts associated with the Program. You can also create Workouts independent of any Program. I'm new to Obj-C fundamentals and am trying to figure out how I should tie in Workouts with their Program (keeping in mind that eventually reporting data will use the relationship between the two).
I've concluded that this can/should be done in 1 of 2 ways and need help learning which is the most efficient:
1) When a Workout is created, see if it originates from a Program or is on it's own (this is how I've done it successfully now). If it's from a program, add a 'WorkoutInProgram' Core Data attribute to the Workout which will store the ProgramName. Then whenever I want to fetch all Workouts in a Program, I just look up the attribute where WorkoutInProgram == ProgramName.
2) Create some sort of Core Data relationship between Workouts and Programs. When a Workout is created within a Program, the relationship between the ProgramName attribute (of the Program entity) and the Workout entity is stored. I spent around an hour trying to figure out this relationship, got confused, and resorted to #1 which worked.
I'm not sure if a Core Data relationship is useful here, I got hung up on the fact that multiple Workouts would be associated with a single Program entity based on ProgramName.
As always, thank you.

Here is roughly what things should look like in XCode. Program.workouts is a To-Many relationship and Workouts.program is an optional To-One relationship.
Generated NSManagedObject subclasses should look like this
//
// Program.h
// CoreDataLibraryApp
//
//
#import <Foundation/Foundation.h>
#import <CoreData/CoreData.h>
#class Workout;
#interface Program : NSManagedObject
#property (nonatomic, retain) NSDate * timeStamp;
#property (nonatomic, retain) NSString * name;
#property (nonatomic, retain) NSSet *workouts;
#end
#interface Program (CoreDataGeneratedAccessors)
- (void)addWorkoutsObject:(Workout *)value;
- (void)removeWorkoutsObject:(Workout *)value;
- (void)addWorkouts:(NSSet *)values;
- (void)removeWorkouts:(NSSet *)values;
#end
//
// Workout.h
// CoreDataLibraryApp
//
//
#import <Foundation/Foundation.h>
#import <CoreData/CoreData.h>
#class Program;
#interface Workout : NSManagedObject
#property (nonatomic, retain) NSString * name;
#property (nonatomic, retain) Program *program;
#end
When you create a new Workout you can set the program attribute like this:
newWorkout.program = selectedProgram;
If you want to get all workouts for a program you do something like this
for (Workout *workout in selectedProgram.workouts) {
NSLog(#" workout is %#", workout.name);
}

What you've done so far is create your own relationship manually, you just aren't using Core Data to manage the relationship. I would recommend creating a one-to-many relationship between Program and Workout. The relationship can be specified as optional so it doesn't have to be populated.
Some benefits to having the relationship specified with Core Data include automatically keeping things in sync if the name of the Program ever changes, being able to specify delete behaviors, and code simplification when it comes to fetching the Program associated with a Workout.
One thing that might be causing confusion (I know it did for me at first) is that you don't specify the relationships based on specific attributes (like you would if you were creating a model in a relational DB). You don't, for example, create a specific attribute for the purpose of linking the two entities together. Instead, when you create your relationship, you might name it "program" in the Workout entity and "workouts" in the Program entity.

Related

IOS/Objective-C/Core-Data: Does new Core Data object come with relationship objects?

I am importing book records from JSON into NSManagedobjects that have their own attributes but also relationships to other entities, authors and publishers.
For each book item that comes down from the cloud via JSON, I create a new bookFromServer object. I store the attributes from JSON into this object. This is simple enough with title, bookid etc.
However, the JSON also contains other information that properly belongs in other entities, ie publisher publisher name, publisher address, author first name author last name, author date of birth etc.
My question, is whether I also have access to "phantom" or uninstantiated managedobjects of the entitites with which my object has a relationship? Or do I need to create properties in the object file for each and every attribute.
Here is the NSObject file for BookFromServer
#import <CoreData/CoreData.h>
#class Books;
#class Authors;
#class Publishers;
#interface BookFromServer : NSObject
#property (nonatomic, retain) NSNumber * bid;
#property (nonatomic, retain) NSString * title;
#property (nonatomic, retain) NSNumber * authorid;
#property (nonatomic, retain) NSNumber * publisherid;
//this is relationship
#property (nonatomic, retain) Authors *author;
//this is relationship
#property (nonatomic, retain) Publishers *publisher;
#end
I would like to store author info in something like author.firstname, not as a separate authorfirstname property in books. So my question is when I instantiate a book object, do I get the use of the attributes in the objects available through the relationships?
My question, is whether I also have access to "phantom" or uninstantiated managedobjects of the entitites with which my object has a relationship? Or do I need to create properties in the object file for each and every attribute.
It's exactly the same as with any other kind of object. Using Core Data doesn't change anything here.
New objects are only created when your code creates them. Core Data never creates a new object implicitly or automatically. So if your managed object has relationships to other managed objects, you need to create the managed objects and then update the objects so that their relationships refer to each other.
Properties of managed objects are available when the object is created, so a string or numeric property exists as soon as the managed object exists.

Relational database in Realm?

I want to create simple relational database in the iOS Realm DB. How can i link user id and there Wishlist product similar to the relational database in SQL. Example like bellow image :
I know i can create 2 separate Realm models (tables) to store user id with time_stamp and in second table for Wishlist where there are user id with each Wishlist products or user id and a Wishlist, where the user has an array of Wishlist. Now i want to store all users with there multiple wishlists. This means that every time the user enters in APP, I have to query every wishlists in existence to see whether its intended for this specific wishlists. The problem is in Wishlist table, it doesn't have any primary key and realm not allowing to create model without primary key.
Does Realm support foreign key concept ? and use of composite key is quit complicated. Is there a more efficient way to do this?
You can use RLMArray , where RLMArray is the container type in Realm used to define to-many relationships.
As mentioned in the official Realm documentation for objective c check example here.
Also go through this link it might help RLMArray doc
RLMArray is used for the relational database concept in realm. You can try like this:
#import <Realm/Realm.h>
#class User;
// User model
#interface User : RLMObject
#property NSString *name;
#property NSString *user_id;
#property RLMArray<Watchlist *><Watchlist> *watchlist;
#end
RLM_ARRAY_TYPE(Dog) // define RLMArray<Dog>
// Watchlist model
#interface Watchlist : RLMObject
#property NSString *id;
#property NSInteger *activity;
#property NSInteger *cost;
#end
RLM_ARRAY_TYPE(Watchlist) // define RLMArray<Person>
// Implementations
#implementation User
#end // none needed
#implementation Watchlist
#end // none needed
Read data from realm :
RLMResults *watchlistDB = [Watchlist allObjects];
WatchlistDB = [realm_data objectAtIndex:index];
RLMArray *realm_array = WatchlistDB.watchlist;

Core Data Installation

I am using core data to save data from web services in my app. On the first time of running, app creates the core data instance and attributes and properties and save all the data. My question is that, when the application runs second time or many times, Is the core data creates its instance and properties and save all data again, or again and again? I am sorry if my question is not relevant.
Thanks
If the Webservice + code for storing data to coredata gets called every time you run app, core data will store objects again and again
You can solve this by 2 ways
If your data from server remains the same, you can set a flag and check that coredata insertion should execute only once
If you data from server may keep on changing, you can Update data instead of inserting it again to avoid duplicate records.
If u want to make sure the data is unique, u should make sure the data object should have a unique key.
For example:
#interface Person : NSManagedObject
#property (nonatomic, retain) NSNumber * pid;
#property (nonatomic, retain) NSString * name;
#end
The property of Person.pid should be unique. It means that u can only get one person max with the appointed pid.
So before u insert new object, u should query the db with NSFetchRequest(NSPredicate) like this:
NSNumber *aimPid;// the person's pid
NSPredicate *predicate = [NSPredicate predicateWithFormat:[NSString stringWithFormat:#"pid == %#", aimPid]];
If person exist, then just update and save.
If person not exist, then insert a new one and save.
More:https://developer.apple.com/library/mac/documentation/Cocoa/Reference/CoreDataFramework/Classes/NSFetchRequest_Class/

iOS Core Data Saving MOC issue due to Validation rules context

I'm using Magical Record with the Core Data framework, and I've run into issues saving deleted objects from my MOC. I have a Patient NSManagedObject that has a set of Notes NSManagedObjects, so MOs look like like so:
Patient.h
#interface Patient : NSManagedObject
#property (nonatomic, retain) NSSet *notes;
#end
#interface Patient (CoreDataGeneratedAccessors)
- (void)addNotes:(NSSet *)values;
- (void)removeNotes:(NSSet *)values;
#end
Notes.h
#interface Note : NSManagedObject
#property (nonatomic, retain) NSDate * creationDate;
#property (nonatomic, retain) NSString * noteText;
#property (nonatomic, retain) Patient *patient;
#end
I also have validation rules to make sure the noteText property is not null or empty. Now in my view controller in the viewDidLoad method I'm creating a new note managed object using:
Note* lNote = [Note MR_createInContext:localContext];
So, the note is created instantly once the view loads, ready for the noteText property to be modified via a UITextView. If the user does not enter any text and presses Save the validation triggers and prevents the save, which is all good.
The problem occurs when I click on my notes archive folder button which is in this same view controller, once pressed, it presents a modal view controller and lets the user either load or delete notes, since I'm trying to delete a note from this archive screen, I have to rollback the previous note I created in the viewDidLoad method, so that I can delete the notes and save the default context, otherwise when I'm trying to save the deleted objects the validation rule for noteText property kicks in from the MOC.
I notice that this is more of a logical or work flow type of problem, but I want to prevent the rollback of the note created in the defaultContext and still be able to save the defaultContext with the deleted notes.
I've tried using different MOC but that presented more issues, one MOC for retrieving the patients and another one for creating notes.
Creating a different managed object context is the correct solution for your problem. A MOC is a "scratchpad" and you need two scratchpads in the scenario you describe. You are essentially interrupting the note creation process with another note editing process.
That being said, you could just delete the empty note and recreate it when the other controller is dismissed. You could also set the note text to #"". There are all kinds of hacky ways to accomplish this, but using two MOCs is the cleanest method.

restkit - having trouble mapping relationships... or something

Setup - using RestKit, along with it's abilities to store data in a CoreData store.
I'm trying to perform two separate GET operations:
issue/:issueId ==> this returns an Issue object, assuming one with that ID exists.
issue/:issueId/comment ==> this returns Comment objects, belonging to the issue matching issueId.
So, for the first call, that just gets an issue back. It will only return comments back if I pass in an extra parameter on the URL. Otherwise, it won't. Of course, if I do ask for it, then the objects get created just fine, and all the objects are connected correctly in my core-data store.
The objects that I'm mapping look like this:
#interface Issue : NSManagedObject
#property (nonatomic) int32_t issueId;
#property (nonatomic, retain) NSSet* comments;
// many other fields not shown.
#end
#interface Comment: NSManagedObject
#property (nonatomic) int32_t commentId;
// many other fields not shown.
#end
Issue has a collection of Comments. Comments don't know about their owning Issue.
So, all I'm trying to do is make it possible for both of these calls to exist.
For example, in our URLs, say "issueId" is 12345. So, if I make one call to http://example.com/issue/12345, I'd like the data to be written to my CoreData store. (This works great, btw). What I would like to happen next is to call "http://example.com/issue/12345/comments", and then have those comments write to the CoreData store, and also be connected to issue-12345, that's already there. That's the part that I'm having trouble with.
If anyone could offer guidance on this, I'd really appreciate it.
After reading this issue on the official repo, I would proceed like follows.
In you Core Data model add the inverse relationship Comment -> Issue, so that your Comment interface looks like
#interface Comment: NSManagedObject
#property (nonatomic, retain) Issue * issue;
#property (nonatomic) int32_t commentId;
// many other fields not shown.
#end
and make that relationship mandatory.
Now you have to setup your mapping adding that relationship, for instance
[issueMapping addRelationshipMappingWithSourceKeyPath:#"comments"
mapping:[self commentMapping]];
If my understanding is correct, RestKit should populate both relationships (the one-to-many Issue -> Comment and its inverse) for you.

Resources