creating an object out of multiple variable types - iphone

I have an NSDictionary that I am passing to a NSObject Class where I pull all of the values out of the dictionary and pass them into their correct types.
For instance NSInteger, BOOL, NSString, char are the types of values I am pulling out of the NSDictionary and putting into their only variables.
My question what is the best way to turn these values into one big object that can then be putt into an array?
I have heard that I can use the class itself as an Object.. But I am not really sure how to do this.
or could I just put them back into a NSDictionary?... but if thats the case do NSDictionaries allow for multiple value types?

Actually, you are in the right path. this is basically MVC architecture way. so you are questioning about M = Model.
Model in here example is class that defines all variables. cut to the point, here's you should do:
-> create a class that contain your variable, with #property & #synthesize name : ClassA.
then you could set object ClassA into dictionary.
ClassA *myClass = [[ClassA alloc] init];
myClass.myString = #"test String";
myClass.myBoolean = True;
[dictionary setObject:myClass forKey:#"myObject"];
[myClass release]; //we no longer need the object because already retain in dictionary.
then retrieve it by :
ClassA *myClass = (ClassA*)[dictionary objectForKey:#"myObject"];
NSLog(#"this is value of myString : %# & boolean : %i",myClass.myString,myClass.myBoolean);

You can put the collection of values in NSDictionary, NSArray, NSMutableArray, etc. Any of the collection types. Or if you have a fixed number of values/types, you can create a class that has a data member for each value/type and put it in that. The class solution would eliminate having to do a lot of casting, but it also only works if there are a fixed number of values/types.
Here is the AppleDoc on collections.

Yeah, You can create a class itself with these as different values as a properties.Once you pass this object to any class you can access those values there by obj.propertyName.Doing by this Lead to create Modal in MVC pattern.
Please let me know if there is doubt.
Test *object = [[Test alloc] init];
object.testBool=true;
object.testString=#"Test";
NSDictionary *passData = [[NSDictionary alloc] initWithObjectsAndKeys:object,#"testObject", nil];
Test *getObject = (Test*)[passData objectForKey:#"testObject"];
NSLog(#"%d",getObject.testBool);
NSLog(#"%#",getObject.testString);
You can customized the init method of Test Class.

Related

Calling properties/instance variables from strings in Objective-C

Basically my view controller has 49 different instance variables of class CircleView (called circleView1, circleView2, ..., circleView49). The CircleView class is a simple subclass of UIImageView and basically returns a circle picture when initialized.
Here is what I am trying to do:
In my implementation for the view controller, I want to be able to select the instance variable using a string, for example let's say I generate a random integer i between 1 and 49, lets say it's 5. I would like to be able to build an NSString using something like [NSString stringWithFormat #"circleView%i",i]; and somehow reach the actual circleView5 instance variable. Is this possible?
P.S. I'm looking for something in the lines of NSClassFromString, but which applies to instance variables or objects.
KVC is your friend. Assuming you have a string with the name of the circleView in it,
NSString *myCircle = [NSString stringWithFormat:#"circleView%i", i];
you access that property on the controller using KVC:
CircleView *theCircle = [self valueForKey:myCircle];
On a side note, you should consider redesigning the object heirarchary; this will be very difficult to maintain, and there are certainly better ways to do it (an array with the CircleView's accessed by index would be my first choice).
Instead of having a pile of variables and trying to access them via a string, use an array (either a primitive C array or an NSArray: I'll demo with an NSMutableArray). Declare a NSMutableArray *circleViews; in your class like you did the circleViewN instances. In your initializer, instead of a bunch of circleViewN = [[CircleView alloc] init];, you'd have something like:
circleViews = [NSMutableArray arrayWithCapacity:50];
for(int i=0; i<50; i++)
[circleViews addObject:[[[CircleView alloc] init] autorelease]];
Then you can access the desired circle with your random int i with [circleViews objectAtIndex:i];.

Adding ivar to an NSManagedObject subclass

I have a subclass of NSManagedObject Class used with Core Data in iPhone. However, I have a temporary "field" (ivar) that I want to add in that Class (but I dont want to persist it in the data-store). Tried to use informal and formal protocol, but both of them give me a "static-variable" like behaviour. (It behaves like a Class Variable rather than Instance Variable). Any suggestion?
My first attempt, created Test "Dummy-class" which is supposedly a subclass of NSManagedObject, then I created Test-category
#interface Test (custom)
NSString *_string ;
- (void)setString:(NSString *)newString;
- (NSString *)string;
#end
Those are the usual setter and getter. This is the way I use the Test class
Test *a = [[Test alloc] init];
Test *b = [[Test alloc] init];
[a setString:#"Test1"];
NSLog(#"%#", [a string]); //This will print out Test1
[b setString:#"Test2"];
NSLog(#"%#", [b string]); //This will print out Test2
NSLog(#"%#", [a string]); //Unfortunately, this will also print out Test2
I could also mess with the NSManagedObject subclass (which is my Entity) directly but I dont think that is the way to do it.
You can't add an instance variable in the (in)formal protocol or in the category.
Any variable definition inside the category is treated as a variable definition at the file level outside the category, so it behaves like a class variable. It's a confusing behavior; I guess the compiler should warn about it.
The standard solution is to add the ivar which holds transient data (which does not persist in the database) in the subclass representing the entity directly, as in:
#interface MyEntity:NSManagedObject{
NSString*stringHoldingTransientSomething;
}
...
#end
and then specifying MyEntity as the class in the Core Data Editor. Note that Core Data does not automatically save ivars in your custom NSManagedObject subclass; it only saves the properties specified in the Core Data model. So you can add as many book-keeping ivars as you want in your custom subclass.

Declaring an object type in an if statement

I'm trying to declare a variable inside an if statement. If the result of a query is YES then the object will be of one type, otherwise it will be of another type. A bit like this...
if (YES) {
ObjectTypeA *object = [[ObjectTypeA] alloc] init];
}
else {
ObjectTypeB *object = [[ObjectTypeB] alloc] init];
}
Once that's done I want to use object with the same methods no matter what type it is. I tried declaring object as an id before the if statement but get an error: member reference type 'struct objc_object *' is a pointer; maybe you meant to use '->'?
I also tried declaring both to be separate objects outside the if and then make the pointer point to whichever it was once I knew. That wouldn't work either.
I know that the compiler is trying to protect me from myself by doing this but in this circumstance I need a way round it please.
Thanks.
The most common pattern for this problem in Cocoa/Cocoa Touch is to define a protocol.
A protocol is a collection of methods that can be implemented by any object.
If you make ClassA and ClassB conform to a protocol containing the methods you need them to respond to then you don't need to worry about which type of object you get.
The idea is "if it looks like a duck and quacks like a duck, then it's probably a duck".
You can use dynamic typing and create your objects depending on the outcome of your query, but ensure that the resulting object conforms to a particular protocol, like so:
id <MyProtocol> myObject;
if (YES)
myObject = [[ClassA alloc] init];
else
myObject = [[ClassB alloc] init];
[myObject myMethod];
[myObject release];
I think this code should work well:
id obj = nil;
if (YES) {
obj = [[ObjectTypeA] alloc] init];
} else {
obj = [[ObjectTypeB] alloc] init];
}
[obj performSelector:#selector(YOUR_METHOD) withObject:YOUR_OBJECT];
You want dynamic typing :)
The way around this is to declare a third object that both of these inherit from
OR
You could use the adapter pattern and create an object that accepts both of these objects as a member and then wrap the functions you wish to call into that object
good luck!
--> These are genral OO solutions; I'm not a Objective-C developer

Obj-C: Creating an object with a String name

Hey all. I know this sounds simple, but I can't find a way to do it. I have a method in Obj-C that takes in a NSString and then should create a new class with the String as its title.
-(DataModel *)createDataModel:(NSString *)dataModel_name {
DataModel *[initWithString:dataModel_name] = [[DataModel alloc] init];
}
I know I have some problems in this. For starters, I don't know how to define a return on an object whose name could change. Second, I know this doesn't compile considering the initWithString method is wrong. I just don't know what to do or what method to use so that I can create this DataModel object with the specified name...
If your title is setup correctly, as a property:
-(DataModel *)createDataModel:(NSString *)dataModel_name {
DataModel *model = [[DataModel alloc] init];
model.title = dataModel_name;
return model;
}
That would require in your datamodel.h:
#interface DataModel {
NSString *title;
}
#property (nonatomic, retain) NSString *title;
#end
And in your .m:
#implementation DataModel
#synthesize title;
#end
But your question isn't clear if your real purpose is trying to instantiate different classes based on the dataModel_name or if you just have a single generic class with a title that should be set to dataModel_name.
Depending on what you want to do, there are different answers. If you really want different classes based on the name, then you should do things differently. You can use the Cocoa specific type: id, to return any object from a method. Then the method, NSClassFromString() to create the object:
- (id)createDataModel:(NSString *)dataModel_name {
id model = [[NSClassFromString(dataModel_name) alloc] init];
[model setTitle:dataModel_name];
return model;
}
Or you can define a Protocol (Interface in java parlance) that declares the features of your data model. Your method would return that instead.
NSClassFromString() will do what you want. Also, initially declaring variables as type id allows you to set their explicit type later on. So:
id dataModel = [[NSClassFromString(dataModel_name) alloc] init];
To locate or create a new class:
Class arbitraryClass = NSClassFromString(dataModel_name);
if ( nil == arbitraryClass ) arbitraryClass = objc_allocateClassPair( [DataModel class] , [dataModel_name UTF8String] , 0 );
To create a new instance of an object with your newly created class:
DataModel *modelWithArbitratyClassName = [[arbitraryClass alloc] init];
Creating new classes at runtime is not usually a good idea.
So, it seems you want to dynamically add an Instance variable to an object at runtime. You don't get this for free. CALayer and CAAnimation can do something similar to this, you can read about it here
You could add similar functionality to your own objects using Key-value-coding, and more specifically the method valueForUndefinedKey. There will be some KVC specific caveats so you should really make sure you are familiar with and understand KVC. Take a look at this, it might be just want you want.
A dictionary is used to store the value and key, and to retrieve the value when you try to access it.

Objective C: How do I make an NSMutableSet of NSMutableDictionaries, and have them be unique based on one of the dictionary values?

The reason I'm asking this is because right now I use an NSMutableSet of integers and a corresponding NSMutableArray to store the rest of the data, but I think I'm not using the language right. Here's my code:
In the init function:
self.markerList = [[NSMutableArray alloc] init];
self.markerIdSet = [[NSMutableSet alloc] init];
And the function that updates the set and array:
- (void) addMarker: (RMMarker*)marker AtLatLong:(CLLocationCoordinate2D)point {
if (![self.markerIdSet member: [node objectForKey:#"id"]]) {
[self.markerIdSet addObject:[node objectForKey:#"id"]];
[self.markerList addObject:marker];
}
}
I would be a bit wary of having a mutable object as part of a key in a set as if the object changes its hash code etc could change but the set would not know about it ( unless you make the addMarker remve the object and then add it back with the new hash code)
However in your example can't you just use a dictionary (or am I missing something?)
self.markerDict = [[NSMutableDictionary alloc]init];
- (void) addMarker: (RMMarker*)marker AtLatLong:(CLLocationCoordinate2D)point {
if ([nil != [self.markerDict [node objectForKey:#"id"]]) {
[self.markerDict setValue:marker forKey:[node objectForKey:#"id"]];
}
}
The NSMutableSet contains unique elements. Uniqueness is determined by the hash and isEquals methods, so in order to do what you want, you should either subclass or delegate an NSMutableDictionary and in your own concrete class implement these methods so that the specific key you require is the equality and hash factor.
Don't make an NSMutableSet of NSMutableDictionary directly; make a custom class that has an NSMutableDictionary property. This custom class should implement -isEqual: and -hash in terms of your id—i.e. this object will be equal to another object if the ids are equal, and two objects with the same id will have the same hash.
More documentation with regard to -isEqual: and -hash.