So I'm a Flash guy and I'm trying to convert the following code to Object C:
var slot:Object = new Object();
slot.id = i;
slot.xPos = 25*i;
slot.yPos = 25*i;
slot.isEmpty = False;
// push object to array
arrGrid.push(slot);
Later I can override like:
arrGrid[0].isEmpty = True;
I can't seem to find a reference to creating generic objects in Object C. Can someone help?
Well assuming you are doing something with the iphone or mac in cocoa you can simply subclass NSObject (the base class in objective-c).
You need a .h and .m so for you example it would be something like:
(Note that I used slotId instead of id because id is a keyword in objective-c)
Slot.h
// Slot.h
#interface Slot : NSObject {
NSInteger slotId;
float xPos;
float yPos;
BOOL empty;
}
#property NSInteger slotId;
#property float xPos;
#property float yPos;
#property BOOL empty;
#end
// Slot.m
#import "Slot.h"
#implementation Slot
#synthesize slotId;
#synthesize xPos;
#synthesize yPos;
#synthesize empty;
#end
That defines a simple Slot object with 4 properties which can be accessed using dot notation such as:
s = [[Slot alloc] init];
s.empty = YES;
s.xPos = 1.0;
s.yPos = 1.0;
There are a lot of variations for which data types you use and how you define the properties, etc depending on what kind of data you are dealing with.
If you wanted to add a slot object to an array one simple example:
// create an array and add a slot object
NSMutableArray *arr = [NSMutableArray array];
Slot *slot = [[Slot alloc] init];
[arr addObject:slot];
// set the slot to empty
[[arr objectAtIndex:0] setEmpty:YES];
If you're only using this Object instance to store named values, you can use an instance of NSMutableDictionary instead, although you'll need to wrap your integer values with NSNumber instances:
NSMutableDictionary * obj = [NSMutableDictionary dictionary];
[obj setObject: [NSNumber numberWithInt: i] forKey: #"id"];
[obj setObject: [NSNumber numberWithInt: i*25] forKey: #"xPos"];
[obj setObject: [NSNumber numberWithInt: i*25] forKey: #"yPos"];
[obj setObject: [NSNumber numberWithBool: NO] forKey: #"isEmpty"];
Then you'd add these to an NSMutableArray allocated using [NSMutableArray array] or similar:
[array addObject: obj];
To get the integer/boolean values out of the dictionary, you'd do the following:
int i = [[obj objectForKey: #"id"] intValue];
BOOL isEmpty = [[obj objectForKey: #"isEmpty"] boolValue];
Related
I'm trying to create an NSDictionary full of arrays in the implementation file of my model but my code hasn't worked yet. I want to create arrays that are lists of types of dogs and cats and then add those arrays to a dictionary with keys called DOG and CAT. Here is my code:
#implementation wordDictionary
#synthesize catList = _catList;
#synthesize dogList = _dogList;
#synthesize standardDictionary =_standardDictionary;
- (void)setCatList:(NSMutableArray *)catList
{
self.catList = [NSMutableArray arrayWithObjects:#"lion", #"puma", #"snow leopard", nil];
}
- (void)setDogList:(NSMutableArray *)dogList
{
self.dogList = [NSMutableArray arrayWithObjects:#"pit bull", #"pug", #"chihuahua", nil];
}
-(void)setStandardDictionary:(NSMutableDictionary *)standardDictionary
{
[self.standardDictionary setObject: _catList forKey:#"CAT"];
[self.standardDictionary setObject: _dogList forKey:#"DOG"];
}
- (NSString*)selectKey
{
NSInteger keyCount = [[self.standardDictionary allKeys] count];
NSInteger randomKeyIndex = arc4random() % keyCount;
NSString *randomKey = [[self.standardDictionary allKeys] objectAtIndex:randomKeyIndex];
return randomKey;
}
#end
This code is the model. The model is hooked up to my view controller such that when a user taps a button, the NSString returned from randomKey is displayed in a label on the screen. So the text will read either CAT or DOG. Here's the code for that:
- (IBAction)changeGreeting:(UIButton*)sender {
NSString *chosenKey = [self.dictionary selectKey];
NSString *labelText = [[NSString alloc] initWithFormat:#"%#", chosenKey];
self.label.text = labelText;
}
Unfortunately when I tap the button on the simulator I get an error message saying: Thread 1:EXC_ARITHMETIC (code=EXC_1386_DIV, subcode=0x0) at NSInteger randomKeyIndex = arc4random() % keyCount; and it appears that I'm getting it because neither my NSArray nor my NSDictionary have any objects inside of them.
Does anyone have any idea why my NSArray and NSDictionary haven't been populated?
Thanks very much.
The simple answer is that there isn't any code here that calls the methods to set the arrays or dictionary.
But the real underlying issue is that there are a couple of bad 'patterns' going on here that you should fix:
In your setter methods (setCatList:, setDogList:, setStandardDictionary:) you're not setting the properties in question to the values that are passed in. For example, you should be setting catList to the passed in "catList" variable.
- (void)setCatList:(NSMutableArray *)catList
{
if (_catList != catList) {
[_catList release];
_catList = [catList retain];
}
}
Then you should have some kind of "setup" happening, usually in a method in the view controller like viewDidLoad:
[wordDictionary setCatList:[NSMutableArray arrayWithObjects:#"lion", #"puma", #"snow leopard", nil]];
// and more for the other two setters
Alternately, you can set these default values in the init for the wordDictionary class:
- (id)init {
self = [super init];
if (self) {
[self setCatList:[NSMutableArray arrayWithObjects:#"lion", #"puma", #"snow leopard", nil]];
}
return self;
}
The former is better in most cases, but you may have a good reason to pre-populate your model for all instances of the class.
Assuming you called setCatList:, setDogList: and setStandardDictionary: before. Probably that causing is this :
NSString *chosenKey = [self.dictionary selectKey];
change into this :
NSString *chosenKey = [self selectKey];
UPDATE
I'm trying to make your life easier. no need to create your object if you don't need the most.
- (NSMutableArray*)getCatList
{
return [NSMutableArray arrayWithObjects:#"lion", #"puma", #"snow leopard", nil];
}
- (NSMutableArray*)getDogList
{
return [NSMutableArray arrayWithObjects:#"pit bull", #"pug", #"chihuahua", nil];
}
-(NSMutableDictionary*)getStandardDictionary
{
NSMutableDictionary *standardDictionary = [NSMutableDictionary new];
[standardDictionary setObject:[self getCatList] forKey:#"CAT"];
[standardDictionary setObject:[self getDogList] forKey:#"DOG"];
return [standardDictionary autorelease];
}
- (NSString*)selectKey
{
NSMutableDictionary *standardDictionary = [self getStandardDictionary];
NSInteger keyCount = [[standardDictionary allKeys] count];
NSInteger randomKeyIndex = arc4random() % keyCount;
NSString *randomKey = [[standardDictionary allKeys] objectAtIndex:randomKeyIndex];
return randomKey;
}
- (IBAction)changeGreeting:(UIButton*)sender {
// NSString *chosenKey = [self selectKey];
//NSString *labelText = [[NSString alloc] initWithFormat:#"%#", chosenKey];
self.label.text = [self selectKey]; //no need to convert it to NSString again
}
Two things to consider:
I don't see you calling these:
setCatList:(NSMutableArray*)catList;
setDogList:(NSMutableArray*)dogList;
You use self.catList and self.dogList, but neither of those are synthesized, instead you have beatList and meList synthesized
Change the synthesizes to the catList and dogList, and make sure you call the set list methods, and then you should make some progress.
i need to create and destroy dynamically dictionaries, or arrays,
and have them as instance variables,
so for example, [pseudocode]
*.h
nsmutableDictionary myDictn???
nsstring arrayn ???
how to create an instance dictionarie, and property, that dinamically get created and destroyed?, and how to refer to it?
*.m
n = 0
create container {
myDictn alloc init
n+1
}
other {
myDictn addobject#"data" forKey"myKey"
}
destroy container {
myDictn release
n-1
}
So what intend to show is that i would like to have myDict1, myDict2...
if created,
or destroy them if needed
thanks a lot!
To create dictionaries dynamically & add entries to them you could do this -
NSMutableDictionary *dictResult = [[[NSMutableDictionary alloc] init] retain];
[dictResult setValue:result forKey:#"key"];
Here result can be anything. NSString or NSArray etc. Also using retain retains this object & causes a memory leak if not explicitly released. Instead try to do autorelease that way ios takes care of releasing the object when its no longer referred to. You do that like so -
NSMutableDictionary *dictResult = [[[NSMutableDictionary alloc] init] autorelease];
This is all you need to create dictionaries dynamically.
I think what you're asking for is how to have multiple mutable dictionaries dynamically created. You haven't said where the numbering scheme is coming from, so you may need to modify this solution for your purposes.
What you want is an array or dictionary of dictionaries.
Make one NSMutableDictionary called something like dictionaryContainer. Then, when you want to create dictionary number 7, do
NSMutableDictionary *aDictionary = [NSMutableDictionary new];
[dictionaryContainer setObject:aDictionary forKey:[NSNumber numberWithInt:7]];
To recall that dictionary, do
NSMutableDictionary *theSameDictionary = [dictionaryContainer objectForKey:[NSNumber numberWithInt:7]];
You don't have to hard code the 7, you can get it from anywhere and pass it in as an integer variable.
If I got your question correctly, this is pretty easy
#interface MyClass {
NSMutableDictionary *dict;
NSMutableArray *arr;
}
#property (nonatomic, retain) NSMutableDictionary *dict;
#property (nonatomic, retain) NSMutableArray *arr;
#end
Implementation file
#import "MyClass.h"
#implementation MyClass
#synthesize dict;
#synthesize arr;
- (id) init {
self = [super init];
if (self) {
dict = [[NSMutableDictionary alloc] init];
arr = [[NSMutableArray alloc] init];
}
return self;
}
- (void) dealloc {
[dict release];
[arr release];
[super dealloc];
}
- (void) otherStuff {
[dict setObject: #"value" forKey: #"key"];
[arr addObject: #"item"];
}
#end
usage from another class:
...
MyClass *instance = [MyClass new];
[instance.dict setObject: #"value" forKey: #"key"];
NSLog(#"Array items: %#", instance.arr);
[instance release];
...
I want to create a nested array or multidimensional array.
In my data is,
FirstName class year dept lastName
Bob MBA 2000 Comp Smith
Jack MS 2001 Comp McDonald
NSMutableArray *section = [[NSMutableArray alloc] init];
I want to put my data into the section Array.
Eg:
section[0] = [FirstName,LastName];
section[1] = [class, year, dept];
So how can i put the values into array like that.
Please help me out.
Thanks
I would recommend creating a custom data storage class. You could call it PDPerson.h You'll also need the .m file. For each property, do something like this:
In the .h: Declare each of your properties like so:
#interface PDPerson : NSObject{
}
#property(nonatomic, retain) NSString *firstName;
#property(nonatomic, retain) NSString *lastName;
#property(nonatomic, retain) NSString *class;//May want to consider renaming
#property(nonatomic, retain) NSString *year;
#property(nonatomic, retain) NSString *dept;
#end
Then in the .m:
#implementation
#synthesize firstName, lastName;
#synthesize class, year dept;
-(void)dealloc{
[firstName release];
[lastName release];
[class release];
[year release];
[dept release];
}
Each time you want to create a new "Person" in your array, do this:
PDPerson *person = [[PDPerson alloc]init];
You can then easily set the properties of the object like so:
person.firstName = #"John";
person.lastName = #"Smith";
person.class = #"Math";
person.year = #"1995";
person.dept = #"Sciences";
And retrieve them:
firstNameLabel.text = person.firstName;
The nice thing about these objects is that all you have to do now is add the person object to your array:
NSMutableArray *personArray = [[NSMutableArray alloc] init];
[personArray addObject:person];
NSArray *section1 = [NSArray arrayWithObjects: #"1,1", #"1,2", #"1,3", nil];
NSArray *section2 = [NSArray arrayWithObjects: #"2,1", #"2,2", #"2,3", nil];
NSArray *section3 = [NSArray arrayWithObjects: #"3,1", #"3,2", #"3,3", nil];
NSArray *sections = [NSArray arrayWithObjects: section1, section2, section3, nil];
int sectionIndex = 1;
int columnIndex = 0;
id value = [[sections objectAtIndex:sectionIndex] objectAtIndex:columnIndex];
NSLog(#"%#", value); //prints "2,1"
Be warned, this isn't a flexible way of storing data. Consider using CoreData or creating your own classes to represent the data.
You can just nest multiple NSArray instances within an NSArray.
For example:
NSMutableArray* sections = [[NSMutableArray alloc] init];
for (int i = 0; i < numberOfSections; i++)
{
NSMutableArray* personsInSection = [[NSMutableArray alloc] init];
[sections insertObject:personsInSection atIndex:i];
for (int x = 0; x < numberOfPersons; x++)
{
Person* person = [[Person alloc] init];
[personsInSection insertObject:person atIndex:x];
}
}
This may seem like overkill when coming from languages such as C++ or Java, where multidimensional arrays can be created simply by using multiple sequare brackets. But this is way things are done with Objective-C and Cocoa.
I have now tried to get this to work for a few hours but just cannot get it right.
I have the following code:
NSDictionary* dict = [NSDictionary dictionaryWithObjectsAndKeys:
[NSArray arrayWithObjects:#"currentGame1", #"currentGameType1", #"currentGameQuestion1", #"currentGameRightAnswers1", #"currentGameType1", #"numberOfType0Games1", #"type0Results1", #"numberOfType1Games1", #"type1Results1",#"numberOfType2Games1", #"type2Results1",nil], #"Player1",
[NSArray arrayWithObjects:#"currentGame2", #"currentGameType2", #"currentGameQuestion2", #"currentGameRightAnswers2", #"currentGameType2", #"numberOfType0Games2", #"type0Results2", #"numberOfType1Games2", #"type1Results2",#"numberOfType2Games2", #"type2Results2",nil], #"Player2",
[NSArray arrayWithObjects:#"currentGame3", #"currentGameType3", #"currentGameQuestion3", #"currentGameRightAnswers3", #"currentGameType3", #"numberOfType0Games3", #"type0Results3", #"numberOfType1Games3", #"type1Results3",#"numberOfType2Games3", #"type2Results3",nil], #"Player3",nil];
[dict writeToFile:#"/Users/MikaelB/Desktop/xxxxPlayer.plist" atomically: TRUE];
NSMutableDictionary *readDict = [[NSMutableDictionary alloc] initWithContentsOfFile:#"/Users/MikaelB/Desktop/xxxxPlayer.plist"];
NSLog(#"readDict: %#", readDict);
NSLog(#"= = = = = = = = = = = = = = = = = = =");
for (NSArray *key in [readDict allKeysForObject:#"Player6"]) {
NSLog(#"Key: %#", key);
}
The for loops is just part of the tests i do to try to extract data from the dictionary and is one of many different ways i have tested.
My question is if there is someone nice who can show me how to extract a record (key + objects) and NSLog it?
Cheers
If you are trying to save the game state for a number of players, you may be going about it the wrong way. I don't want to stand in the way of your current progress, but I would like to point out some avenues for improvement.
First point: NSDictionary objects (and plists, for that matter) can store data in a tree structure, so there is no need to have a different set of keys for each user:
NSDictionary* dict = [NSDictionary dictionaryWithObjectsAndKeys:
[NSArray arrayWithObjects:#"currentGame", #"currentGameType", ..., nil],
#"player1",
[NSArray arrayWithObjects:#"currentGame", #"currentGameType", ..., nil],
#"player2",
..., nil];
Second point: Taking this one step further, I think what you really want is another complete dictionary for each player:
NSMutableDictionary * playerInfo;
playerInfo = [NSMutableDictionary dictionaryWithCapcity:0];
[playerInfo setObject:#"1" forKey:#"currentGame"];
[playerInfo setObject:#"2" forKey:#"currentGameType"];
[playerInfo setObject:#"what's up?" forKey:#"currentGameQuestion"];
...
NSMutableDictionary * allPlayers;
allPlayers = [NSMutableDictionary dictionaryWithCapcity:0];
NSInteger playerNum;
for (playerNum = 1; playerNum <= 6; playerNum++) {
NSString * key = [NSString stringWithFormat:#"Player%d", playerNum];
[allPlayers setObject:playerInfo forKey:key];
}
Now, after saving and reading the allPlayers dictionary, you would access a single record as follows:
NSDictionary * player2Info = [readDict objectForKey:#"player2"];
NSLog(#"%#", player2Info); // show all keys and values for player 2
NSLog(#"%#", [player2Info valueForKey:#"currentGame"]; // show a single value
Third point: If you are storing a game state for several users, the proper way to do it (from an OO point of view) is to create a Player class and then load and save instances of this class. At a glance, it would look like this:
#interface Player {
NSString * currentGame;
NSString * currentGameType;
NSString * currentGameQuestion;
...
}
#property (nonatomic, copy) NSString * currentGame;
#property (nonatomic, copy) NSString * currentGameType;
#property (nonatomic, copy) NSString * currentGameQuestion;
...
- (void)loadFromDictionary:(NSDictionary *)dict;
- (NSDictionary *)saveAsDictionary;
#end
#implementation Player
#synthesize currentGame;
#synthesize currentGameType;
#synthesize currentGameQuestion;
...
- (void)loadFromDictionary:(NSDictionary *)dict {
[self setCurrentGame:[dict objectForKey:#"currentGame"]];
[self setCurrentGameType:[dict objectForKey:#"currentGameType"]];
[self setCurrentGameQuestion:[dict objectForKey:#"currentGameQuestion"]];
...
}
- (NSDictionary *)saveAsDictionary {
return [NSDictionary dictionaryWithObjectsAndKeys:
currentGame, #"currentGame";
currentGameType, #"currentGameType";
currentGameQuestion, #"currentGameQuestion";
...
nil];
}
#end
Now, you can load and save players as follows:
Player * player1 = [[[Player alloc] init] autorelease];
Player * player2 = [[[Player alloc] init] autorelease];
...
NSDictionary * players = [NSDictionary dictionaryWithObjectsAndKeys:
[player1 saveAsDictionary], #"Player1",
[player2 saveAsDictionary], #"Player2",
...
nil];
// save dictionary
[players writeToFile:...
// load dictionary
NSDictionary * readDict = ...
[player1 loadFromDictionary:[readDict objectForKey:#"Player1"]];
[player2 loadFromDictionary:[readDict objectForKey:#"Player2"]];
...
See also:
Nested arrays in Objective-C ( NSMutableArray ) (player objects)
What's the best way to store and retrieve multi-dimensional NSMutableArrays? (property list serialization)
Well, your dictionary doesn't contain #"Player6", just 1-3.
And #"Player6" is your key, so you want the object not the key!
for (NSArray *object in [dict objectForKey:#"Player1"]) {
NSLog(#"Value: %#", object);
}
I would like to fill in the class variables in a loop from an dictionary. What I want to do is having the dictionary key as a class variable and assign the class variable (the dictionary key) the value from dictionary... something like this:
+(void) initWithDictionary:(NSDictionary *)dic {
MyClass *classInstance = [[[self alloc] init] autorelease];
NSArray *allKeys = [dic allKeys];
for(NSUInteger i = 0; i < [allKeys count]; i++)
{
id classVariable = [allKeys objectAtIndex:i];
classInstance.classVariable = [dic objectForKey:[allKeys objectAtIndex:i]];
}
return classInstance;
}
It does not work, because I do not know how to assign the class variable from the string.
Thanks for answer, I am returning a JSON string that gives me an NSDictionary with keys and values. I am trying to fill this values to my class, let's say DetailObject. I want to use later in the project the DetailObject.id, DetailObject.description, etc. I would like to do it in a loop, becouse now I have to write this:
+ (id) initWithDiccionary :(NSDictionary *)dic//;
{
//Instantiating an object of this class... that's okay.
DetailObject *classInstance = [[[self alloc] init] autorelease];
classInstance.id = [dic objectForKey#"id"];
classInstance.desc = [dic objectForKey#"desc"];
etc... etc...
return classInstance;
}
What I want is to parse the dictionary from JSON to my object and respective variables and values that comes from dictionary in a loop, because if the JSON dictionary changes, I just add the new class variable with the same name of the returned dictionary key...
I do not know if I have explained it well...
Your question is very very unclear and I have no idea what you're trying to do or why. But just looking at your code I can tell you already that it's definitely not doing what you want.
//There should be no semicolon after "dic" below.
//Also, you should be returning a MyClass or an id.
- (id) initWithDiccionary :(NSDictionary *)dic//;
{
//Instantiating an object of this class... that's okay.
MyClass *classInstance = [[[self alloc] init] autorelease];
//Getting all the keys from the dictionary, seems fine...
NSArray *allKeys = [dic allKeys];
//Looping through all the keys in the dictionary, seems okay...
for(NSUInteger i = 0; i < [allKeys count]; i++)
{
//Storing the current key.
id classVariable = [allKeys objectAtIndex:i];
//Assigning the class's property "classVariable" to match the current key's value.
//No reason to say "[allKeys objectAtIndex:i]" again, though.
classInstance.classVariable = [dic objectForKey:classVariable];
}
//Returning something when you have no return type above (void) is wrong.
return classInstance;
}
Your code will just assign classInstance.classVariable to be equal to [allKeys objectAtIndex:[allKeys count]-1]. Your loop is pointless.
After I actually annotated your code though I think I have some idea of what you want. Basically you want to assign the variables with names matching the keys in the dictionary the values in the dictionary. i.e. if there is a key called "superKey" then you want to find the variable within classInstance (classInstance.superKey) and assign it the value in the dictionary that matches superKey. That's what you want, right?
Well, the only way I know of to do that is to use a big switch statement or a bunch of if statements. Make some function within MyClass like this:
- (void) assignProperty:(id)property toValue:(id)value
{
if (property == #"superKey")
{
self.superKey = value;
}
else if (property == #"lameKey")
{
self.lameKey = value;
}
//etc.
}
Then you just call [classInstance assignProperty:classVariable toValue:[doc objectForKey:classVariable]] and the job will be done.
But having told you all that...
Why would you ever want to do what you're doing? Want to know a much better way of doing this? Give MyClass its own NSDictionary. Basically all you are doing is defeating the entire purpose of the dictionary. Why? They are incredibly fast to access and can store whatever you want. There is no reason not to use one. So just do this:
- (id) initWithDiccionary :(NSDictionary *)dic
{
MyClass *classInstance = [[[self alloc] init] autorelease];
classInstance.dictionary = dic;
return classInstance;
}
Voila.
Enter Key-Value Coding. The following is an example of how you could achieve your desired outcome:
#interface MyClass : NSObject
#property (nonatomic, retain) NSString *aString;
#property (nonatomic, retain) NSNumber *aNumber;
#property (nonatomic, retain) NSString *yetAnother;
- (id)initWithDictionary:(NSDictionary *)dictionary;
#end
#implementation MyClass
#synthesize aString;
#synthesize aNumber;
#synthesize yetAnother;
- (id)initWithDictionary:(NSDictionary *)dictionary {
if ((self = [super init])) {
[self setValuesForKeysWithDictionary:dictionary];
}
return self;
}
// dealloc is left as an exercise for the reader
#end
You could use this class as follows:
NSDictionary *dictionary = [NSDictionary dictionaryWithObjectsAndKeys:
#"my string", #"aString",
[NSNumber numberWithInt:42], #"aNumber",
#"strings!", #"yetAnother", nil];
MyClass *myClass = [[MyClass alloc] initWithDictionary:dictionary] autorelease];
// yay!
You can thank Objective-C's dynamism for that. :)