How to model an n-to-n relationship in Objective-C? - objective-c

I am trying to model an n-to-n relationship in Objective-C. Suppose I have two entities: Movie and Theater. A Movie has an array of Theaters and a Theater has an array of Movies. How do I do this in Objective-C to 1) get the relationship correct and 2) make sure memory is managed correctly.

On Apple platforms you have access to Core Data, a very nice persistence framework.

You can use SQLLitePersistentObjects:
It allows you to define code like the following:
#import "SQLLitePersistentObjects.h"
#interface CFCategory : SQLLitePersistentObject {
NSString *name;
CFRegion *region; // where region is another subclass of SQLLitePersistentObject
}
#property(nonatomic, retain, readwrite) NSString *name;
#property(nonatomic, retain, readwrite) CFRegion *region;
#end
And use it in your code:
CFRegion *region = [CFCategory findByRegion:[myRegionObject pk]];
Memory and persistence is automatically handled by the framework. However, if you are working with large data sets be sure to use NSArray objects with the paired arrays functionality instead of allocating and deallocating hundreds or thousands of SQLLitePersistentObjects.

Related

Possible to set multiple parent entities for Core Data NSManagedObject?

I have created the following example Core Data NSManagedObject subclasses:
PBCommentableObject : NSManagedObject // to allow comments on object
#property (nonatomic, retain) NSSet *pBcomments; // unordered set of PBComment objects
PBComment : PBCommentableObject // to allow comments on a comment
#property (nonatomic, retain) PBCommentableObject *target;
PBList : PBCommentableObject // to allow comments on a list
#property (nonatomic, retain) NSOrderedSet *pBorderedItems; // ordered set of PBListableObject objects
PBString : PBListableObject // to allow strings to be added to lists
#property (nonatomic, retain) NSString *pBtext;
PBListableObject : ???? // I'd like both PBList and PBString to be PBListableObjects
#property (nonatomic, retain) PBList *pBlist;
The problem I am having is that I would like the following behavior:
Lists (PBList) that can hold an ordered list of strings (PBString) or other lists (PBList).
Allow comments (PBComment) on lists (PBList) and other comments (PBComment) but not strings (PBString)
Is this possible to do? I am currently trying to build the Core Data model via the visual interface in Xcode; and while I could conceive of using categories, I don't know how I would do so without Xcode spitting out a warning when I fail to define a relationship via the visual editor.
I think you are stretching the idiom of inheritance. All this "listable" and "commentable" results in quite unreadable complexity.
The validation of allowing or disallowing comments, lists or what have you, can be modeled with simply using (boolean) attributes and relationships. Try to think of only concrete objects such as "Comment" or "String" and model the lists with the attribute sets.

Creating a transient relational property

I think this is a simple issue but I have somehow leaked object in core data. I have a simple one to one relation in core data.
Person <--------> Address
-name -city
-email -country
The person model was relatively simple with just few attributes. But, I wanted to add the getter in Person class to access the city and country from the person class itself. So, I did something like,
#interface Person:NSManagedObject
#property(nonatomic, strong) NSString *name;
#property(nonatomic, strong) NSString *email;
#property(nonatomic, strong) Address *address;
-(NSString*)city;
-(NSString*)country;
#end
#implementation Person
-(NSString*)city{
[self willAccessValueForKey:#"address"];
NSString *c = [self valueForKeyPath:#"address.city"];
[self didAccessValueForKey:#"address"];
}
-(NSString*)country{
[self willAccessValueForKey:#"address"];
NSString *c = [self valueForKeyPath:#"address.country"];
[self didAccessValueForKey:#"address"];
}
#end
With these getter I have been able to access the city with just simple getters in Person model as;
person.city and person.country
But, I feel this is not the correct way to do it. How do I implement this feature to ensure that the memory is not leaked.
You can not access city or country directly from Person,
you can access like....
Person.Address.city
Person.Address.country
and no need of implement the:
-(NSString*)city;
-(NSString*)country;
You forgot the return statements in the code, but I guess they are there in the actual code you are using.
I do not see any leak in the code itself. Remember however that you are responsible for faulting everything when done as Core Data relationships inherently create retain cycles. See Core Data And Retain Cycles
As Ganee says, you can just access
person.address.city
but if you absolutely need the city method, you should use the generated properties:
- (NSString*)city {
return address.city;
}
though this hides your relationship access so make sure that's what you want.
In regards to your memory leak, you need a really, really, really good reason to not use ARC for new projects.

Iterate over key values in a Restkit Model

I'm guessing there is a simple solution here, but I've tried some things and nothing seems to work out. What I'd like to do is be able to iterate through the stored values in a model so I can present them in different ways graphically.
I can access the web service and store the data perfectly. As part of a larger model, I have a goals model with various goals that can be set.
GoalsModel looks like
#class RoundGoalsModel;
#interface RoundGoalsModel : NSObject {
NSNumber* _scoreGoal;
NSNumber* _parsGoal;
NSNumber* _birdiesGoal;
}
#property (nonatomic, retain) NSNumber* scoreGoal;
#property (nonatomic, retain) NSNumber* parsGoal;
#property (nonatomic, retain) NSNumber* birdiesGoal;
#end
All the data is in there as expected. Now all I need to do is figure out how to loop through the keys and values in the Model so I can do things like present different icons for different goals, check if a value is null, etc. I'm trying to avoid having to access each individually with a bunch of conditional statements.
I've tried casting it to an array and other things that dont seem to work. Any advice or suggestions pointing me in the right direction would be awesome. Thanks!
Your problem isn't a RestKit problem it's just an issue with your design. Since you already have your data placed into the individual fields you could just add a new field to return them in an array.
.h
#property(readonly, retain)NSDictionary *allProperties;
.m
#synthesize allProperties;
- (NSDictionary*)allProperties
{
return [NSDictionary dictionaryWithObjectsAndKeys: _scoreGoal, #"scoreGoal", _parsGoal, #"parsGoal", _birdiesGoal, #"birdiesGoal", nil];
}
Then you could easily iterate over the dictionary and do whatever you want.

#synthesize syntax when overriding accessors

I am doing a value object / Entity, that holds data for my model.
I get the data from a web service as JSON, now, instead of moving all the different objects from the parsed JSON over into different properties on my Entity. i.e. reading out the NSString for the #"name" key and setting it to [Entity setName:[JSONDictionary objectForKey:#"name"] etc. My Entity has one actual property,
NSDictionary *dataDictionary, this property hold the JSON dictionary as it left the parser.
Now when I need the name value I write an accessor that looks like this:
- (NSString*) name {
return [self.dataDictionary objectForKey:#"name"];
}
This is nice, I don't have to do any work unless there is a request for that particular property.
Now my question is how do I best tell the compiler that the accessor exists, but does not hold a "real" property.
I have this in my interface:
#property(nonatomic, retain) NSString *name;
And the #synthesize in my implementation, but this seems to create an overhead in my logic. Objective C will, as far as I understand, make a room in memory for me to store an object of type NSString when I do the #property(nonatomic, retain) and technically I don't need this as I am already storing this value in the the NSDictionary *dataDictionary
If I make it #dynamic I guess I would also have to provide a setter, which I would never need.
So, Is there a syntax that lets me create the illusion to all objects accessing the Entity that these are "normal" properties, but internally in the Entity not alloc/store unnecessary objects or write more code than is needed?
Declare a name method in your interface, not a property.
- (void)name;

c-style member vars in obj-c

I've noticed that I cannot use the #property / #synthesize for member vars that are arrays in obj-c. For instance the member var int mVar[5] cannot use the #property/#synthesize.
However, I've noticed that I can set these vars simply by not using self.mVar[n] but instead using mVar[n].
Can someone explain why this works, if this is good or terrible practice, and what alternative I should use if it is not good practice?
Properties are syntactic sugar for set/get-style methods. Passing arrays in as parameters and out as return values via these methods is fraught with semantic and performance problems, so they probably just put them in the too-hard basket and deliberately excluded them.
As regular data members, arrays don't exhibit these difficulties because you are accessing them directly rather than copying them in and out via methods.
If you want to make the contents of an array accessible as a property (which you should only need to do if you want to make the contents public), you can expose them as:
#property (readonly) int *vars;
#property (readonly) int numVars;
Or you could do the Objective-C thing:
#property (nonatomic, retain) NSArray *vars;
But then you would have to create lots of NSNumber objects (ick).