I want store 4 name of book from url (.php?info=1&b=1 display name of first book) in array and run that code and use these names.
also I want create object of class and dedicate first name to first object (second name to second object and etc)
this is my code:
#import "Recipe.h"
for (int i = 1; i <= 4; i++)
{
Recipe *booki = [Recipe new]; // create object
NSLog(#"%d,%#",i,booki);
NSString *c = [[NSString alloc]initWithContentsOfURL:[NSURL URLWithString:[NSString stringWithFormat:#"http://192.168.1.102:81/temp/book.php?info=1&b=%d",i]]];
NSMutableArray *b = [[NSMutableArray alloc]init];
[b addObject:c];
NSLog(#"%#,%#",c,b);
booki.name = [NSString stringWithString:c];
recipes = [NSMutableArray arrayWithCapacity:4];
//NSLog(#"%#",recipes);
recipes = [NSMutableArray arrayWithObjects:booki, nil];
in this code I see only one name in object and its last name of book
The issue seems to be this.
recipes = [NSMutableArray arrayWithObjects:si, nil];
Since you are looping inside a for loop. If you want to have all names. You need to create an array outside the for loop. Instead of creating a new array each time add object to it.
if(!recipes){
recipes = [NSMutableArray array];
}
[recipes addObject:si];
Related
So, I'm trying to build an array of CGPoints by breaking an NSString, typically look like this:
31.241854,34.788867;31.241716,34.788744;31.242547,34.787585;31.242661,34.787719
Using this code:
- (NSMutableArray *)buildPolygon:(NSString *)polygon
{
NSMutableArray *stringArray = [[NSMutableArray alloc] init];
[stringArray addObject:[polygon componentsSeparatedByString:#";"]];
NSMutableArray *polygonArray = [[NSMutableArray alloc] init];
for (int i=0; i < polygonArray.count; i++)
{
NSArray *polygonStringArray = [[NSArray alloc] init];
polygonStringArray = [[stringArray objectAtIndex:i] componentsSeparatedByString:#","];
CGFloat xCord = [[polygonStringArray objectAtIndex:0] floatValue];
CGFloat yCord = [[polygonStringArray objectAtIndex:1] floatValue];
CGPoint point = CGPointMake(xCord, yCord);
[polygonArray addObject:[NSValue valueWithCGPoint:point]];
}
NSLog(#"return polygonArray: %#", polygonArray);
return polygonArray;
}
But eventually I get an empty array.
What I'm doing wrong?
You're defining polygonArray as an empty array just before the start of your for loop. You should define polygonArray like:
NSArray *polygonArray = [polygon componentsSeparatedByString:#";"];
And you don't even need to bother with that stringArray variable.
You have confusion over alloc & init, and one simple typo...
The confusions first:
NSMutableArray *stringArray = [[NSMutableArray alloc] init];
This creates a new NSMutableArray and stores a reference to it in stringArray. All good so far.
[stringArray addObject:[polygon componentsSeparatedByString:#";"]];
And this obtains a reference to an NSArray ([polygon componentsSeparatedByString:#";"]) and adds it as a single element to the mutable array referenced by stringArray. There is nothing wrong per se with this, but it is not what you want in this case - you just want the array returned by componentsSeparatedByString:. You do this with:
NSArray *stringArray = [polygon componentsSeparatedByString:#";"];
Which takes the reference returned by componentsSeparatedByString: and stores it in the variable stringArray - no alloc or init required as you are not creating the array yourself. You don't even own this array, so if you are using MRC there is no need to release it later.
NSArray *polygonStringArray = [[NSArray alloc] init];
Now this allocates an immutable empty array and stores a reference to it in polygonStringArray. This is not a very useful array, as it contains nothing and cannot be modified! But you don't keep it around long...
polygonStringArray = [[stringArray objectAtIndex:i] componentsSeparatedByString:#","];
This obtains a reference to an array from componentsSeparatedByString: and stores it in polygonStringArray. If you are using MRC this will cause a leak - your pointless zero-length array created above will leak, and a new zero-length array will be created and leaked every time around the loop.
You are confused over allocation - you only need to allocate things you are creating; when you receive a reference to an already allocated object you only need to store that reference. (If using MRC you may also need to retain/release/autorelease it as well - but let's stick with ARC.) So all you needed here was:
NSArray *polygonStringArray = [[stringArray objectAtIndex:i] componentsSeparatedByString:#","];
Now your code is almost correct, just one typo:
for (int i=0; i < polygonArray.count; i++)
Well you are filling polygonArray in this loop and it starts off as empty, what you need is stringArray.count.
HTH
Man,just like the topic above if i want to make change directly with an exiting mutable array.
i want to know how to add a new array to an exiting array in a mutable array
Thanks for any advise!
The problem which you mentioned to add an array into another array which is contained in the NSMutableArray, it can be done like
NSMutableArray *childArray = [self.ParentArray objectAtIndex:index];
[childArray addObjectsFromArray:yourArrayToAdd];
hope that will solve your problem
Suppose we have an NSMutableArray named numbersArray
numbersArray = [[NSMutableArray alloc]initWithObjects:#"1",#"2",#"3",#"4",#"5",#"6",#"7",#"8",#"9",#"10" , nil];
if you want to add an array to it instead of the original, lets say that array is an random array of its own content:
NSMutableArray *temp = [[NSMutableArray alloc] initWithArray:numbersArray];
for(NSUInteger i = [numbersArray count]; i > 1; i--) {
NSUInteger j = arc4random_uniform(i);
[temp exchangeObjectAtIndex:i-1 withObjectAtIndex:j];
}
numbersArray = temp;
the last line give the numbersArray the content of the temp array
and we can do that with
numbersArray = [temp copy];
for the index exchange you can use exchangeObjectAtIndex as follow:
[numbersArray exchangeObjectAtIndex:0 withObjectAtIndex:3];
[numbersArray exchangeObjectAtIndex:1 withObjectAtIndex:4];
[numbersArray exchangeObjectAtIndex:2 withObjectAtIndex:5];
i'm new to obj-c (this is my first day class eheh) and i'm trying to change a label with a random string from a multidimensional array. plus, every time the button is hitten you switch the array. i know it's a bit odd eheh… this is the IBAction:
UIButton *button = (UIButton *)sender;
NSMutableArray *firstArray = [NSMutableArray array];
[firstArray addObject:#"foo"];
NSMutableArray *secondArray = [NSMutableArray array];
[secondArray addObject:#"bar"];
NSMutableArray *frasi = [NSMutableArray array];
[frasi addObject:firstArray];
[frasi addObject:secondArray];
NSMutableArray *array = [NSMutableArray arrayWithObjects:[frasi objectAtIndex:[button isSelected]], nil];
NSString *q = [array objectAtIndex: (arc4random()% [array count] )];
NSString *lab = [NSString stringWithFormat:#"%#", q];
self.label.text = lab;
all works, but the new label is
( "foo" )
instead of just foo (without quotes)... probably i mess in the last block of code...
ty
So, you create 2 mutable arrays, then add them to a new mutable array frasi. Then you get one of those two arrays and use it as the single element (because you use arrayWithObjects: instead of arrayWithArray:) of a new array array.
So array is an array that contains a single array element (instead of an array of strings as you may believe).
When you get an object from array, it's always the same single object that was used to initialize it: either firstArray or secondArray.
So you get an array of strings where you expect a string. When using stringWithFormat:, the specifier %# is replaced with the string description of that object.
A string returns itself as its own description. But the description of an array is the list of all its elements separated with commas and surrounded by parenthesis, which is why you get ( "foo" ).
So instead or creating unneeded arrays, you may just replace all the 8th last lines with this:
NSArray *array = [button isSelected] ? secondArray : firstArray;
self.label.text = [array objectAtIndex:arc4_uniform([array count])];
Actually u have array within array
Replace this line with yours:
NSString *q = [[array objectAtIndex: (arc4random()% [array count] )] objectAtIndex:0];
I have a singleton class where I set up a NSMutableDictionary called completedLevels.
This is how I set it up (in the init method of my singleton):
NSString *mainPath = [[NSBundle mainBundle] bundlePath];
NSString *levelConfigPlistLocation = [mainPath stringByAppendingPathComponent:#"levelconfig.plist"];
NSDictionary *levelConfig = [[NSDictionary alloc] initWithContentsOfFile:levelConfigPlistLocation];
completedLevels = [[NSMutableDictionary alloc]init];
NSMutableDictionary *levelSets = [[NSMutableDictionary alloc]init];
NSMutableDictionary *levels = [[NSMutableDictionary alloc]init];
NSMutableDictionary *stats = [[NSMutableDictionary alloc]init];
[stats setObject:[NSNumber numberWithBool:NO] forKey:#"levelDone"];
[stats setObject:[NSNumber numberWithInt:0] forKey:#"stars"];
[stats setObject:[NSNumber numberWithInt:0] forKey:#"time"];
[stats setObject:[NSNumber numberWithInt:0] forKey:#"bestTime"];
for (int i = 1; i<=18; i++) {
[levels setObject:stats forKey:[NSString stringWithFormat:#"level%d", i]];
}
for(int i= 1; i<=15;i++){
NSString *lvlSet = [NSString stringWithFormat:#"levelSet%d", i];
[levelSets setObject:levels forKey:lvlSet];
}
NSArray *categoriesArray = [levelConfig objectForKey:#"categoriesArray"];
for (int i=0; i<[categoriesArray count]; i++) {
NSString *category = [[levelConfig objectForKey:#"categoriesArray"]objectAtIndex:i];
[completedLevels setObject:levelSets forKey:category];
}
I want to explain my doings:
My intention was to create a dictionary in this form:
category = {
levelSet1 ={
level1 ={
bestTime = 0;
levelDone = 0;
stars = 0;
time = 0;
};
level2={
bestTime = 0;
levelDone = 0;
stars = 0;
time = 0;
};
.
.
.
}
levelSet2 ={
level1 ={
bestTime = 0;
levelDone = 0;
stars = 0;
time = 0;
};
level2={
bestTime = 0;
levelDone = 0;
stars = 0;
time = 0;
};
.
.
.
}
.
.
.
}
%d in the case of levelSet are integers from 1 to 15.
%d in the case of level are integers from 1 to 18.
I have several categories, and thus multiple sets of the example above.
This works well and upon calling NSLog, the dictionary appears in my console as it should.
The problem, however, arises when I want to change some entries in my dictionary as shown in the example below:
NSString *category = [[GameStateSingleton sharedMySingleton]getCurrentCategory];
NSString *levelSet = [NSString stringWithFormat:#"levelSet%d",[[GameStateSingleton sharedMySingleton]getSharedLevelSet]];
NSNumber *currentLevel = [NSNumber numberWithInt:[[GameStateSingleton sharedMySingleton]getSharedLevel]];
NSString *levelString = [NSString stringWithFormat:#"level%d", [currentLevel intValue]];
NSMutableDictionary *categories = [[NSMutableDictionary alloc]initWithDictionary:
[[GameStateSingleton sharedMySingleton]getCompletedLevels]];
[[[[categories objectForKey:category]objectForKey:levelSet]objectForKey:levelString]setObject:[NSNumber numberWithBool:YES] forKey:#"levelDone"];
[[GameStateSingleton sharedMySingleton]setCompletedLevels:categories];
NSLog(#"%#",[[GameStateSingleton sharedMySingleton]getCompletedLevels]);
To explain that:
When the player is done with a level, I want the levelDone entry to change its value. But when I log it afterwards, suddenly all levelDone entries of all categories change to the BOOLEAN value of 1. Why is that ?
------------------- update -----------------------
completedLevels = [[NSMutableDictionary alloc]init];
NSMutableDictionary *levelSets = [[NSMutableDictionary alloc]init];
NSMutableDictionary *levels = [[NSMutableDictionary alloc]init];
NSMutableDictionary *stats = [[NSMutableDictionary alloc]init];
[stats setObject:[NSNumber numberWithBool:NO] forKey:#"levelDone"];
[stats setObject:[NSNumber numberWithInt:0] forKey:#"stars"];
[stats setObject:[NSNumber numberWithInt:0] forKey:#"time"];
[stats setObject:[NSNumber numberWithInt:0] forKey:#"bestTime"];
for (int i = 1; i<=18; i++) {
NSMutableDictionary *statsCopy = [stats mutableCopy];
[levels setObject:statsCopy forKey:[NSString stringWithFormat:#"level%d", i]];
[statsCopy release];
}
for(int i= 1; i<=15;i++){
NSString *lvlSet = [NSString stringWithFormat:#"levelSet%d", i];
NSMutableDictionary *levelsCopy = [levels mutableCopy];
[levelSets setObject:levelsCopy forKey:lvlSet];
[levelsCopy release];
}
NSArray *categoriesArray = [levelConfig objectForKey:#"categoriesArray"];
for (int i=0; i<[categoriesArray count]; i++) {
NSString *category = [[levelConfig objectForKey:#"categoriesArray"]objectAtIndex:i];
NSMutableDictionary *levelSetsCopy = [levelSets mutableCopy];
[completedLevels setObject:levelSetsCopy forKey:category];
[levelSetsCopy release];
}
The part where I retrieve and set it stayed the same...
_________________ SOLUTION ____________________
NSMutableDictionary *mutableCopy = (NSMutableDictionary *)CFPropertyListCreateDeepCopy(kCFAllocatorDefault, (CFDictionaryRef)originalDictionary, kCFPropertyListMutableContainers);
I made deep-copies with this method.
Basically, the problem is that you are setting the level dictionary for each level to the same stats object:
for (int i = 1; i<=18; i++) {
[levels setObject:stats forKey:[NSString stringWithFormat:#"level%d", i]];
}
Instead, you need to set them each to a different mutable copy of the object:
for (int i = 1; i<=18; i++) {
NSMutableDictionary *statsCopy = [stats mutableCopy];
[levels setObject:statsCopy forKey:[NSString stringWithFormat:#"level%d", i]];
[statsCopy release];
}
That should solve the first part for you. However, you also have the same problem with the levelSets. Basically, whenever you add a mutable dictionary, you need to determine whether you are trying to point at the same mutable object (you want to keep them synchronized), or whether you want copies of that mutable object (thus, they act independently). And when you look at building this kind of tree structure, that means you need to look at this at every level.
So, looking at the rest of your code, you'll also need to fix your level sets and categories in the same way, by making a mutable copy inside of each loop and then adding that mutable copy instead of adding the original object. And, since you want to mutate the contents of the contents of the dictionaries, every time you make a mutable copy that contains another mutable dictionary, you need to make that copy at each depth.
You are going to have to choose between building these things depth-wise or doing a deep copy. There's another question:
deep mutable copy of a NSMutableDictionary
That covers deep copies of mutable dictionaries pretty well. Alternatively, you can invert the building of the structure so that instead of making copies, you build each dictionary except for stats which you can easily copy.
The deep copy creates copies of each of the mutable entries all the way down to the farthest leaf nodes. If you think about the NSMutableDictionaries as a tree with the base of the tree at the top ( completedLevels in your case) and the leaves as the elements of the stats NSMutableDictionaries that you copy, you want to individually manipulate every element of the tree, whether it is the leaf node or any intermediate.
An illustration could be made as follows, with this representing the contents of MyDictionary:
Top-A:
Second-A-1
Second-A-2
Top-B:
Second-B-1
Second-B-2
To recap, you have the MyDictionary at the top, which has 2 keys (Top-A,Top-B), each of which is associated with a separate NSMutableDictionary object. Each of those NSMutableDictionaries has 2 keys, each associated with a separate object.
When you make a -mutableCopy of MyDictionary, the result is a new NSMutableDictionary with 2 keys (Top-A,Top-B), each associated with an NSMutableDictionary. However, these NSMutableDictionary objects are actually the same objects as the ones in MyDictionary. This is a shallow copy, meaning that there is a new top-level object (the mutable copy of MyDictionary), but that objects associated with each of the keys in the new dictionary are the same objects as were associated with the keys in MyDictionary. As such, if you change Top-A in the copy be associated with a different NSMutableDictionary, then the Top-A in MyDictionary and the copy will no longer be the same. But, if you change the value associated with Second-A-1, it will change both in MyDictionary and the copy of MyDictionary because Top-A points at a single object.
When you make a deep copy, the utility copies every element of every dictionary individually, which means that the copy of MyDictionary will have a separate Top-A, Second-A-1, Second-A-2,Top-B, etc. from the ones that exist in MyDictionary, and therefore, you can change the values of any of the dictionaries (no matter how deep) without fear of changing other objects.
I've created an object, and now I'm trying to create an array full of these objects. I've tried a few different things with no success.
How can I do this?
You can do it one of two ways, with NSArray or NSMutableArray.
id obj1, obj2, obj3;
// This creates a static array
NSArray *array = [NSArray arrayWithObjects: obj1, obj2, obj3, nil];
// This creates a dynamic array
NSMutableArray *mutarray = [NSMutableArray array];
[mutarray addObject:obj1];
[mutarray addObject:obj2];
[mutarray addObject:obj3];
NSMutableArray * arrayOfFoos = [NSMutableArray array];
for (int i = 0; i < 100; ++i) {
Foo * f = [[Foo alloc] init];
[arrayOfFoos addObject:f];
[f release];
}
You can use an NSArray, take a look at Apple's documentation.
If you wanna add them incrementally consider using a mutable collection like an NSMutableArray (here in the doc)