objective-c "generic" type for #property for use with multiple subclasses - objective-c

i'm not sure of the most eloquent way to state this but i will give it my best. i have created a custom class that is a generic object with some properties. i have created a couple subclasses to extend that and make them more specific than the superclass. so for the sake of example i will throw out some generic example code that may or may not be proper syntax only to illustrate what i would like to accomplish.
#interface Vehicle : NSObject
#property (nonatomic) int wheels;
- (id)initWithNumberOfWheels:(int)wheels;
#end
from there i create some subclasses for same "car" & "truck" which give more detail to the class.
#interface Car : Vehicle
#property (nonatomic) BOOL convertible;
#property etc...
#end
and...
#interface Truck : Vehicle
#property (nonatomic) BOOL is4x4;
#property (nonatomic) int numberOfDoors;
#end
so here is where it gets interesting. i want to create another class that allocates those objects but i want the "type" of vehicle to be determined in the init method but use the same #property variable. so for example (and again, this is all garbage code just to give a visual representation)
Road.h
#import "Car.h"
#import "Truck.h"
#interface Road : NSObject
#property (strong, nonatomic) NotSureWhatToUseHereToMakeThisWork *myRide;
// doesn't work: #property (strong, nonatomic) id myRide;
// doesn't work: #property (strong, nonatomic) Vehicle *myRide;
- (id)initWithCars;
- (id)initWithTrucks;
#end
Road.m
#implementation Road
- (id)initWithCars
{
//standard init code...
myRide = [[Car alloc] initWithNumberOfWheels:4];
myRide.convertable = NO;
}
- (id)initWithTrucks
{
//standard init code...
myRide = [[Truck alloc] initWithNumberOfWheels:6];
//yes, some trucks have more than 4 wheels
myRide.is4x4 = YES;
}
#end
the bottom line is if i use the superclass in the #property it doesn't get the subclass properties obviously. basically i want to keep all this as generic and reusable as possible. it doesn't make since to make a special "road" class just for cars & one for trucks. a road is a road after all. is there anyway to do what i am after? is there a better way to do something like this? the primary purpose is to have objects that inherit specific properties for specific situations only. the reason i don't want to make extra #properties is i don't want those visible if they aren't applicable to the situation.
edit:
i added a couple extra snippets to show what i tried before even posting this question that didn't work.
answer: the correct "answer" if anyone is curious is located in CRD's response in the "Addendum". the reason this works is the type "id" can only call methods and does not inherit properties. so rather the workaround (i say it that way, as i was researching this, came to the conclusion this is not good programming and should probably be avoid if possible) would be to use the accessor methods to get/set the property.
id mySomethingObject = [[SomeClass alloc] init...];
[mySomethingObject setPropertyMethod]...; //sets value
[mySomethingObject propertyMethod]...; //gets value
rather than trying to use...
mySomethingObject.property = ; //set
mySomethingObject.property; //get
as stated in the correct answer, if your class you allocated "id" to does not respond to that method your program will crash.

You appear to be confusing a number of issues.
First there is the type of an instance vs. the type of variables which hold references to instances. When an object is created is it of some specific type and that types does not change[*]. Variables also have a type, and that does not change either. Subtyping/inheritance allows you to store a reference to an object of some type, T, in a variable of some other type, S, provided S is a supertype of T.
Second there is static vs. dynamic typing. While Objective-C uses dynamic typing, where the actual type of objects used in some operation is determined at run time, the compiler itself uses static typing, where types are determined during compilation, to aid in writing correct programs. Sometimes the compilers static checking will just produce warnings, but in other cases the compiler will refuse to compile something. In particular property references are compiled based on static typing.
In your example this means you cannot directly reference a property of Car on an object referenced by a variable of type Vehicle *, even if you know the referenced object is a Car - as at compile time all that is known is that is it a Vehicle.
The solution is to first test the actual type of the referenced object and then introduce a local variable of the more precise type, or use a lot of casts. For example:
// (a) create an object of type Car (for a Reliant Robin ;-))
// (b) create a variable of type Car and store in it a reference to the created Car
Car *myCar = [[Car alloc] initWithNumberOfWheels:3];
// Create a variable of type Vehicle and store in it the reference stored in myCar
// The created instance is *still* a Car
Vehicle *myRide = myCar;
// See if myRide is a Car and then do something
if ([myRide isKindOfClass:Car.class])
{
// create a variable of type Car to avoid having to continually cast myRide
Car *myCarRide = (Car *)myRide; // due to if above we know this cast is valid
if (myCarRide.isConvertible) ...
To do this without the intermediate variable you use a cast:
...
// See if myRide is a Car and then do something
if ([myRide isKindOfClass:Car.class])
{
if (((Car *)myCarRide).isConvertible) ...
Which shows why the intermediate variable approach is better!
As a final example, you write your initWithTrucks method like this:
- (id)initWithTrucks
{
//standard init code...
Truck *myTruck = [[Truck alloc] initWithNumberOfWheels:6];
//yes, some trucks have more than 4 wheels
myTruck.is4x4 = YES;
// Store the reference to the created Truck in myRide
myRide = myTruck;
}
HTH
Addendum
From your comments it seems you may be looking for dynamic typing and do not wish to the compiler to perform any static typing. This is (partially) supported, but not using the dot notation for properties - you must use the getter and setter methods directly.
First, in Road you declare myRide to be type id:
#interface Road : NSObject
#property id myRide;
The id type means two things (a) any object reference and (b) do not statically check a method exists on the object. However the compiler must know that a called method exists on some object, and it will still perform static type checks on the arguments to the method - so its not complete dynamic typing (however you could pass id typed expressions or declare your methods to take arguments of type id of course...).
Second you make all references to properties use the getter or setter methods directly and do not use the dot notation (for non-property methods you just call them as usual). E.g.:
- (id)initWithTrucks
{
//standard init code...
myRide = [[Truck alloc] initWithNumberOfWheels:6];
//yes, some trucks have more than 4 wheels
[myRide setIs4x4:YES];
}
If you make a call such as [myRide setIs4x4:YES] and myRide is referencing a Car object then you will get a runtime error.
The general recommendation is to stick as much as possible with the compiler's static typechecking.
[*] We will ignore any runtime magic, there be dragons. In normal code objects never change type.

You have to use the type "Vehicle" and then cast your object with "Truck" or "Car" to get the specific properties

the most generic architecture would be to create a VehicleProtocol, that any class could implement. you still could have a Vehicle class that implements the protocol and subclass from it (similar to NSObject implementing the NSObject protocol), or let independent classes implement it. the road would have a property #property (strong) id<VehicleProtocol> myRide.
A complete example of the later architecture: no vehicle super class, but all a VehicleProtocol
#import <Foundation/Foundation.h>
#protocol VehicleProtocol <NSObject>
#property (nonatomic) NSUInteger wheels;
#end
#interface Car : NSObject <VehicleProtocol>
#property (nonatomic) BOOL convertible;
#property (nonatomic) NSUInteger wheels;
-(id)initWithNumberOfWheels:(NSUInteger) numberOfWheels;
#end
#implementation Car
-(id)initWithNumberOfWheels:(NSUInteger) numberOfWheels
{
if (self = [super init]) {
_wheels = numberOfWheels;
}
return self;
}
#end
#interface Truck : NSObject <VehicleProtocol>
#property (nonatomic) BOOL is4x4;
#property (nonatomic) int numberOfDoors;
#property (nonatomic) NSUInteger wheels;
-(id)initWithNumberOfWheels:(NSUInteger) numberOfWheels;
#end
#implementation Truck
-(id)initWithNumberOfWheels:(NSUInteger) numberOfWheels
{
if (self = [super init]) {
_wheels = numberOfWheels;
}
return self;
}
#end
#interface Road : NSObject
#property (strong) id<VehicleProtocol> myRide;
#end
#implementation Road
#end
int main(int argc, const char * argv[])
{
#autoreleasepool {
NSArray *vehicles = #[[[Car alloc] initWithNumberOfWheels:4], [[Car alloc] initWithNumberOfWheels:3], [[Truck alloc] initWithNumberOfWheels:10]] ;
for (id v in vehicles) {
if ([v isKindOfClass:[Truck class]]) {
[v setIs4x4:YES];
}
}
Road *road = [[Road alloc] init];
road.myRide = vehicles[0];
NSLog(#"%#", road.myRide);
road.myRide = vehicles[2];
NSLog(#"%#", road.myRide);
NSObject *obj = [[NSObject alloc] init];
road.myRide = obj; // warning in this line
NSLog(#"%#", road.myRide);
}
return 0;
}
Sure it might have more lines of codes than with "classical subclassing", but there are less dependencies. Instead the classes agree on a contract to fulfill. Here the contract only requires the objects to have any number of wheels.
Note that I create a Road and assign first a car and than a truck (I also show how to identify cars and trucks via -isKindOfClass:), both works without any warning or error, as Car and Truck completely fulfill the contract. Than I assign a plain NSObject. Here the compiler warns, as he recognizes that NSObject does not implement the protocol. Though it is not an compiler error, as the compiler does not know, if you will use any protocol specific method on that object.
In case of a plain NSObject assigned to myRide, this line
NSLog(#"%# %ld", road.myRide, (unsigned long)road.myRide.wheels);
will lead to a runtime crash (as an NSObject instance does not respond to wheel) — but at compile time it will not even trigger a warning.

Storing a Car in a variable of type Vehicle * does not remove the object's Car properties — the Car will still be able to access all of its state normally — it just means that you can't access the properties through that variable.
But that's the basic idea here, isn't it? You want this class to be able to handle all Vehicles, and that's what it's doing — it's only showing you the functionality available to all Vehicles. So you can have the interface necessary for interaction with a generic Vehicle in the Vehicle class, and implement the methods in your subclasses to do the class-appropriate behavior when called, and everything will work.
If the issue is specifically creating new instances of a specific class that you want to treat generically from that point on, you can use a statically typed local variable and assign to the generically typed variable once it's set up.
For example, let's say we have a game where there are human players and AI players, and the human player can give himself an advantage by making AI players take more damage. We could do this:
#interface Combatant : NSObject
#property(nonatomic, strong) NSString *name;
#property(nonatomic) int hitPoints;
- (void)takeDamage:(int)damageAmount;
#end
#implementation Combatant
- (void)takeDamage:(int)damageAmount {
self.hitPoints -= damageAmount;
}
#end
#interface HumanCombatant : Combatant
#property(nonatomic, strong) UserID *userID;
- (id)initWithUserID:(UserID *)theID;
#end
#implementation HumanCombatant
- (id)initWithUserID:(UserID *)theID {
if ((self = [super init])) {
_userID = [theID retain];
}
}
- (void)takeDamage:(int)damageAmount {
[super takeDamage: damageAmount];
NSLog(#"Human took %d damage, has %d health remaining", damageAmount, self.hitPoints);
}
#end
#interface AICombatant : Combatant
#property(nonatomic) double damageMultiplier;
#end
#implementation AICombatant
- (void)takeDamage:(int)damageAmount {
int modifiedDamage = damageAmount * self.damageMultiplier;
[super takeDamage: modifiedDamage];
NSLog("AI took %d damage, has %d health remaining", modifiedDamage, self.hitPoints);
}
#end
Then, in most of our game code, we can use a variable typed as a Combatant *, and when you send it takeDamage:, it will do the right thing for the type of combatant it is. Our external code that calls the object a Combatant * will not be able to directly access an AICombatant's damageMultiplier property, because the other code doesn't know whether the Combatant is an AICombatant, but the object will still have that property and will behave correctly for its class.

Make it a Vehicle* and make each class implement type to return a constant indicating that class's type.
#property (nonatomic, strong) Vehicle* yourRide;
...
if (yourRide.type == VehicleConstant_Truck) {
Truck* yourTruck = (Truck*) yourRide;
NSLog(#"This truck %s a 4x4", yourTruck.is4x4 ? "is" : "isn't");
}
To make #vikingosegundo happy, an alternative approach is to do:
if ([yourRide isKindOfClass:[Truck class]]) {
instead of the if statement above.

Related

How can I grant certain classes to set my properties in Objective-C?

Two questions:
How can I allow only certain class to update a property? I tried using category but the NotFriendly class is still able to set the age property via Key-Value.
How come I get the "-[Person setAge:]: unrecognized selector sent" error when I tried to the age property during runtime?
Thanks,
Person.h
#interface Person
#property (readonly) NSString *age;
#end
Person.m
#implementation Person
#synthesize age;
#end
Person+Exclusive.h
#interface Person
#property (readwrite) NSString *age;
#end
Person+Exclusive.h
#implementation Person (Exclusive)
#end
Friendly.m
#import "Person+Exclusive.h"
#interface Friendly
- (void)viewDidLoad {
[super viewDidLoad];
Person *aPerson = [[Person alloc] init];
aPerson.age = #"12"; // -[Person setAge:]: unrecognized selector sent to instance 0x174013e90
}
NotFriendly.m
#import "Person.h"
#interface Friendly
- (void)viewDidLoad {
[super viewDidLoad];
Person *aPerson = [[Person alloc] init];
[aPerson setValue:#"1000000" forKey:#"age"]; // how can I stop this
}
You can't reliably. Any method added to an Objective-C class is visible to everyone in the runtime; available methods are how key-value coding works.
If it's just KVC you want to block then you can override setValue:forKey: and decline to act if the names key is on your blacklist; otherwise call up to super. But classes will still be able to performSelector:withObject: or even drop down to the C runtime, the latter of which you can ultimately do nothing about.
If you are in a position where Person can be responsible for creating those objects that are permitted to talk to it then it can demand an instance as an argument to the setter and continue only if that instance is one you created. Keep a list in one of the weak collections of everything you instantiated.
In any detected failing case, by whatever means, you can manually raise an NSException to create the type of failure you desire.
If it's just for debugging builds and you don't mind a bunch of hassle, you can call [NSThread callStackSymbols] and parse the result to find out which type of class is calling. The text returned has no formally defined format though it's been fairly stable until now; it's explicitly not reliable for release builds. But it shouldn't be too much work to keep it working within debug builds as a diagnostic tool.
Not sure why you would want to do this, but it is an interesting question.
I wonder if you could create a method in person that takes two arguments, age and class. Then when you call it, you use [self class] to pass in the class. Something like this:
- (void)checkTheClassBeforeSettingAge:(NSString *)age withClass:(NSClass *)class {
if (class isKindOfClass:[validClass class]) then {
self.age = age;
} else {
// Error handling code
}
}
Call it with:
checkTheClassBeforeSettingAge:#"12" withClass:[self class];

How to use #property correctly (Setters) within another class

another question i'm trying to use a setter within another class but I seem to get this odd error here is the code below:
AppDataSorting.h
#import <Foundation/Foundation.h>
#interface AppDataSorting : NSObject{
NSString *createNewFood;
NSNumber *createNewFoodCarbCount;
}
#property (readwrite) NSString *createNewFood;
#end
AppDelegate.m
#import "AppDelegate.h"
#implementation AppDelegate
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
// Insert code here to initialize your application
}
- (IBAction)saveData:(id)sender {
NSLog(#"%#", self.foodName.stringValue);
self.createNewFood = self.foodName.stringValue;
NSLog(#"%.1f", self.carbAmount.floatValue);
}
#end
I get the error message in AppDelegate.m which is: Property 'createNewFood' not found on object of type 'AppDelegate *'
Could someone please explain the issue here?
You declare this property:
#property (readwrite) NSString *createNewFood;
In AppDataSorting.h so you can access it like self.createNewFood in AppDataSorting.m file not AppDelegate.m. If you want to call it as you do in AppDelegate.m you have move this line:
#property (readwrite) NSString *createNewFood;
to AppDelegate.h file.
Or if you want to use property from AppDataSorting class in AppDelegate you have to create object and call it on that object:
- (IBAction)saveData:(id)sender {
NSLog(#"%#", self.foodName.stringValue);
AppDataSorting *dSorting = [[AppDataSorting alloc] init];
dSorting.createNewFood = self.foodName.stringValue;
NSLog(#"%.1f", self.carbAmount.floatValue);
}
In -saveData:, self refers to an instance of NSAppDelegate. The createNewFood property is defined on instances of the class AppDataSorting.
Also note that Cocoa/CF naming conventions give special meaning to methods that start with "init", "new" and (to a lesser degree) "create". You probably want to avoid such things in your property names. Details here.
In general, properties should represent conceptual "properties" of an object. So if you had a Person class, it might have a name property, but it wouldn't have a createNewOutfit property.
You need to access createNewFood on an instance of AppDataSorting - but you're trying to access the property on the AppDelegate-class which clearly doesn't implement it.
So you would need to create an instance of AppDataSorting and then access the property like so:
AppDataSorting *instance = [[AppDataSorting alloc] init];
instance.createNewFood = self.foodName.stringValue;
Final notes:
The docs provide a good base of information
If you don't need atomicity you should always declare properties with the nonatomic attribute
createNewFood is not a good name for a property since it suggests a method which creates new food - yet it's only meant to store data (in this case an NSString instance)

Which one is initialized, property or its instance variable

Suppose I have a property called myPropertyName defined in my class MyClassName. Manual memory management is used throughout this post.
MyClassName.h
#import <UIKit/UIKit.h>
#interface MyClassName : NSObject {
#private
NSObject* myPropertyName;
#public
}
#property (nonatomic, retain) NSObject* myPropertyName;
// Some methods prototypes are here
#end
MyClassName.m
#import "MyClassName.h"
#implementation MyClassName
#synthesize myPropertyName;
// Some methods are here
#end
I'm confused with usages such as the place of myPropertyName declaration, its difference between instance variable. For example, what is the difference among these three statement of initialization code, for example, in the customized -(void)init method for my class myClassName.
self.myPropertyName = [[[NSObject alloc] init] autorelease];
This one is calling myPropertyName setter, but I'm not sure what is the name of the instance variable being used in the setter, myPropertyName (since I've declared a #private field named myPropertyName) or _myPropertyName (people say that this one with underbar is the default)?
myPropertyName = [[NSObject alloc] init];
Does this initialize the instance variable of the myPropertyName property? If I don't have #synthesize myPropertyName = _myPropertyName;, would it be wrong since the default instance variable for the property is said to be _myPropertyName.
_myPropertyName = [[NSObject alloc] init];
Is _myPropertyName still declared as the instance variable for my property myPropertyName even if I use #synthesize myPropertyName; and #private NSObject* myPropertyName;?
In my understanding, a property is just a name (such as myPropertyName), there should be some instance variable encapsulated to be used in actual operations in the code, such as assigning values.
First off, I highly recommend reading Apple's documentation on properties, also linked by nhgrif. However, I understand docs can be a bit dense reading material (though Apple's, I find, are not so bad), so I'll give a brief overview of properties here.
I like examples, so I'm going to rewrite your two classes in a bit more current form.
MyClassName.h
#import <UIKit/UIKit.h>
#interface MyClassName : NSObject
#property (nonatomic, strong) NSObject *myPropertyName;
// method prototypes here
#end
MyClassName.m
#import "MyClassName.h"
#implementation MyClassName
// some methods here
#end
The class MyClassName now has a property called myPropertyName of type NSObject *. The compiler will do a lot of work for you for "free" in this instance. Specifically, it will generate a backing variable, and also generate a setter and getter for myPropertyName. If I were to rewrite the two files, and pretend I'm the compiler, including that stuff, they would look like this:
MyClassName.h
#import <UIKit/UIKit.h>
#interface MyClassName : NSObject {
NSObject *_myPropertyName;
}
#property (nonatomic, strong) NSObject *myPropertyName;
- (void)setMyPropertyName:(NSObject *)obj;
- (NSObject *)myPropertyName;
#end
MyClassName.m
#import "MyClassName.h"
#implementation MyClassName
- (void)setMyPropertyName:(NSObject *)obj
{
_myPropertyName = obj;
}
- (NSObject *)myPropertyName
{
return _myPropertyName;
}
#end
Again, all of this is happening for "free": I'm just showing you what's happening under the hood. Now for your numbered questions.
self.myPropertyName = [[[NSObject alloc] init] autorelease];
First of all, you should probably be using Automatic Reference Counting, or ARC. If you are, you won't be allowed to call autorelease. Ignoring that part, this works fine. Excluding the autorelease, this is exactly equivalent to:
[self setMyPropertyName:[[NSObject alloc] init]];
Which, if you look at the second .m file I wrote out, above, will basically translate to:
`_myPropertyName = [[NSObject alloc] init];
myPropertyName = [[NSObject alloc] init];
As written, this code will give a compiler error, since there is no variable called myPropertyName in this class. If you really want to access the instance variable underlying (or, "backing") the myPropertyName property, you can, by using its real name:
_myPropertyName = [[NSObject alloc] init]; // note the underscore
But most of the time, it's better to use the setter, as in point 1., since that allows for side effects, and for Key-Value Coding, and other good stuff.
_myPropertyName = [[NSObject alloc] init];
Oh. Well you got it. See point 2.
You mentioned that:
I'm confused with usages such as the place of myPropertyName declaration, its difference between instance variable. For example, what is the difference among these three statement of initialization code, for example, in the customized -(void)init method for my class myClassName.
In case it hasn't been made clear, a property is something of an abstract concept; its data is stored in a normal instance variable, typically assigned by the compiler. Its access should usually be restricted to the setter and getter, with important exceptions. To keep this answer short, I won't go into more detail than that.
One more thing: as nhgrif mentioned, you don't need to use the #synthesize keyword anymore. That is implicitly understood by the compiler now.
If you're not sure about any of this, post a comment or, better yet, read the docs.
Let's take this example:
#property NSString *fullName;
If in the implementation, we override the setters and getters, and in these setters and getters, we don't use an instance variable fullName, it is never created. For example:
- (NSString *)fullName
{
return [NSString stringWithFormat:#"%# %#", self.firstName, self.lastName];
}
- (void)setFullName:(NSString *)fullName
{
//logic to split fullName into two strings
//self.firstName = etc
//self.lastName = etc.
}
In this example, there is no instance variable for fullName created.
This is according to Apple's Official Documentation
If, however, you don't override both the setter and getter, an instance variable is created.
As a sidenote, you can declare a property readonly, and then simply overriding the getter (without using the variable) will prevent an ivar being created. Likewise, you can declare a property writeonly and just override the setter.

Subclassing iOS Model Objects - Appropriate Design Pattern

I fear this is a rather simple question, but after much googling I think I have overshot my intended result. I believe my question to be related to a design pattern, but alas I could be wrong.
My application calls an RESTful API and gets back what amounts to a list of model objects represented by an NSDictionary. Each of which I will call NNEntity. There are (conceptually) multiple different subtypes of NNEntity. All subtypes of NNEntity share the property of entityID, but each have their own unique properties as well. All instances of NNEntity have a method called readFromDict:(NSDictionary *)d that populates their respective properties. This method is enforced by a protocol that all NNEntity subtypes conform to. It looks like this:
//NNEntity.h
#interface NNEntity : NSObject <NNReadFromDictProtocol>
#property (nonatomic, strong) NSString *entityID;
#end
//NNEntity.m
#implementation NNEntity
- (void)readFromDict:(NSDictionary *)d {
//set common properties from values in d
self.entityID = [d objectForKey:#"ID"];
}
#end
//NNSubEntity1.h
#interface NNSubEntity1 : NSEntity <NNReadFromDictProtocol>
#property (nonatomic, strong) NSString *favoriteColor;
#end
//NNSubEntity1.m
#implementation NNSubEntity1
- (void)readFromDict:(NSDictionary *)d {
[super readFromDict:d];
//set unique properties from values in d
self.favoriteColor = [d objectForKey:#"colorPreference]:
}
#end
//NNSubEntity2.h
#interface NNSubEntity2 : NSEntity <NNReadFromDictProtocol>
#property (nonatomic, strong) NSString *middleName;
#end
//NNSubEntity2.m
#implementation NNSubEntity2
- (void)readFromDict:(NSDictionary *)d {
[super readFromDict:d];
//set unique properties from values in d
self.middleName = [d objectForKey:#"middleName]:
}
#end
I have read various pieces on the use of a Factory or Builder Desing pattern for similar use cases but I am curious if that is necessary in this rather simple case. For example, does my current code end up creating both and instance of NNEntity and NNSubEntity2 if I were to call something like this:
NNEntity *newEntity = [[NNSubEntity2 alloc] init];
//assume dict exists already and is properly keyed
[newEntity readFromDict:dict];
I assume not, but would newEntity have both the common property of entityID as well as the unique property of middleName set correctly? Also, much appreciated if you have thoughts on a better or more efficient design approach.
This looks like exactly how you should be doing it. You have a base class which read in the common attributes, and subclasses which read in their specific attributes.
For example, does my current code end up creating both and instance of NNEntity and NNSubEntity2? NNEntity *newEntity = [[NNSubEntity2 alloc] init];
Nope. When you run this, you instantiate NNSubEntity2 and store the result in a variable typed by it's superclass, which is totally valid. This allows you to call any methods defined on the superclass, but the actual instance is still of the subclass.
Would newEntity have both the common property of entityID as well as the unique property of middleName set correctly?
It sure would. It inherits the instance variables, properties and methods in the superclass.
Rest assured, as far as I can tell this looks sound and is a pattern I've used before.
I do it like this.
// NNEntity.h
#interface NNEntity : NSObject
#property (nonatomic, retain) NSString *entityId;
#end;
// NNEntity.m
#implementation NNEntity
#end;
// NNEntity+KVC.h
#interface NNEnity (KVC)
-(void)setValue:(id)value forUndefinedKey:(NSString *)key {
#end
// NNEntity+KVC.m
#implementation NNEntity (KVC)
-(void)setValue:(id)value forUndefinedKey:(NSString *)key {
// Handle this as appropriate to your app.
// A minimal implementation will throw an exception.
}
#end
And similarly for your various subclasses. You don't (necessarily) need the category on your subclasses.
Then, given NSDictionary *dict with your stuff in it:
NNEntity *entity = [[NNEntity alloc] init];
[entity setValuesForKeysWithDictionary:dict];
Violá! You're done. There are some criticisms of this method, but given a strong implementation of setValue:forUndefinedKey:, I think it's safe and incredibly flexible.
The secrets are in Apple's beautiful Key-Value Coding technology. Essentially, setValuesForKeysWithDictionary: iterates the keys the dict you give it, and for eachinvokes setValue:forKey: in its receiver. It looks something like this (though I'm sure Apple optimizes it under the hood):
-(void)setValuesForKeysWithDictionary:(NSDictionary *)dictionary {
NSArray *keys = [dictionary allKeys];
for (NSString* key in keys) {
[self setValue:[dictionary valueForKey:key] forKey:key];
}
}
I also like this approach because a conversion to CoreData is simple; when you tell CoreData to 'render' your model, it simply overwrites your stubbed model classes, keeping your KVC Category intact. What is more, if your implementation of setValue:forUndefinedKey: is smooth, you can make model changes to your backend without crashing the app (this is a bit of a no-no, but it's not much different from your factory solution).
Of course, I have not addressed your need to selectively choose which class to instantiate. But that is a larger design issue that could be affected even by the design of your API and backend. So I defer.
Also, as you noted in your comment below, the property names must match up. This is a show-stopper for some developers, especially so if you cannot control both the backend and the client.
Give it a try. Feedback is welcome.

Accessing Objects from Class or Method

I have 2 classes in my Cocoa project (Xcode). First is AppDelegate class and the second is a Book class.
In my Book class, I set an integer property in the #interface which is the book's chapters. In its #implementation, I have created objects (ex. Book *firstBook = [[Book alloc]init]) and set their properties (In the Book.m file). Those are my data and will not change.
In my app delegate, I have a method that will fetch what the user selected from an interface item, get the title of the selected item, who's name will be identical to one of those in Book.m. Then a for loop will run to create menu items for a popUpButton so the user can select which chapter to jump to.
The problem I am seeing now is that when I try running the for loop to create menu items, I need the limit amount of the loops. That limit amount is based on the selectedObjectByUser's chapter property (listed in Book.m). How do I access that.
I am sure it will work if I can connect these two together because it works when create the object inside this method(under AppDelegate.h) but the problem is that it is too space consuming and it changes often.
I'm not entirely sure what the situation is here, but let's take a look at some sample code first.
//// Book.h
#interface Book : NSObject
#property (nonatomic, retain) NSString *title;
#property (nonatomic, retain) NSString *author;
#property (nonatomic, assign) NSInteger numberOfPages;
- (id)initWithTitle:(NSString *)aTitle andAuthor:(NSString *)anAuthor;
#end
//// Book.m
#implementation Book
- (id)initWithTitle:(NSString *)aTitle andAuthor:(NSString *)anAuthor {
if ( self = [super init] ) {
self.title = aTitle;
self.author = anAuthor;
}
return self;
}
- (void)dealloc {
self.title = nil;
self.author = nil;
[super dealloc];
}
#end
So in this we establish a class and provide it with 3 properties, title and author (which are both NSString's) and numberOfPages (which is an integer). Within the class we can manipulate those values by calling things such as self.propertyName = value.
This is all well and good, but what actually is happening? Well let's update the header a little more:
//// Book.h
#interface Book : NSObject {
#private
NSString *_title;
NSString *_author;
NSInteger _numberOfPages;
}
#property (nonatomic, retain) NSString *title;
#property (nonatomic, retain) NSString *author;
#property (nonatomic, assign) NSInteger numberOfPages;
- (id)initWithTitle:(NSString *)aTitle andAuthor:(NSString *)anAuthor;
#end
In this, we have just explicitly defined something that the compiler will normally infer through the #property construct. These new additions are what we call instance variables, or ivars, and are where the values you assign to your properties are actually stored.
However, manipulating the ivars can be dangerous if you are not yet 100% comfortable with memory management. Even if you are using ARC, you should still understand how that management works.
So we've now exposed where these properties actually store there data, but what about that #private job? What's it all about? #private is part of a family of keywords that help to denote the "Accessibility Scope" of something. The other two keywords in this family are #protected and #public, however the use of the second two is infrequent, if not unusual. These keywords are responsible for saying where you are allowed to access things. Here's a quick definition of them.
#public Freely accessible from anywhere, even outside of the object itself. However accessing an instance variable directly from outside of its own class is generally considered to be extremely bad practice in the Cocoa development world, hence why you'll find very little on how to do it.
#protected Freely accessible within the class and its own subclasses. Can not be accessed outside of the class/object.
#private Freely accessible within the class, but not anywhere else. Can not be accessed outside of the class/object or even in its subclasses.
So now that we've covered what is actually driving the storage behind a property, let's take a look at using our Book object in another part of the app, such as AppDelegate.
//// AppDelegate.m
#implementation AppDelegate
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
Book *myBook = [[Book alloc] initWithTitle:#"pending title" andAuthor:#"Foo Bar"];
myBook.title = #"My Cool Book";
NSLog(#"%# by %#", myBook.title, myBook.author);
[myBook release];
}
#end
In this we create a new Book object, to put it in more technical terms, we define a variable called myBook with a type of Book and instantiate it. In this we're using the -initWithTitle:andAuthor: method that we created earlier in order to tell the Book object that it should have an initial title and author.
Following this line we then arrive something a little more curious. myBook.title = #"My Cool Book"; You might recall that we had something similar back in Book.m, self.title = aTitle. So what is going on here? Why are we using myBook now rather than self, like we did previously? The reason is because of what self actually is.
self is a keyword provided by the Objective-C runtime, and refers to the current object that you are within. So if we write code inside Book.m, self will refer to the current Book object. If we use self within AppDelegate.m, it will refer to the AppDelegate. So in our earlier code, self was referring to the current Book object much like our myBook object is now referring to a specific Book object. They essentially are equal to each other (not exactly, but thats another area of discussion).
This means any of the properties within Book or methods can be accessed through the myBook variable, much like you would using self inside of Book.m. So we could also do
myBook.title = #"My Book";
myBook.author = #"Baz Quux";
myBook.numberOfPages = 100;
Hope this helps (and answered your question, if not then may it serve as a reference to people wishing to know more about properties and instance variables)