How to convert NSNumbers into integers from an NSArray(iPhone) - iphone

I have a a game for the iphone where the tags of 32 buttons are vital. I am trying to make a feature where it would save these 32 integers into an array so you can play a different game on the board with the same integers(tags) and then later come back to your game with the integers in the same way.(Not asking about multitasking or anything like that) There are some questions like this but none of their answers seem to work.
Right now I have:
savedGame = [NSArray arrayWithObjects: [NSNumber numberWithInt:a2.tag],
[NSNumber numberWithInt:a4.tag],
[NSNumber numberWithInt:a6.tag],
[NSNumber numberWithInt:a8.tag],
[NSNumber numberWithInt:b1.tag],
[NSNumber numberWithInt:b3.tag],
[NSNumber numberWithInt:b5.tag],
[NSNumber numberWithInt:b7.tag],
[NSNumber numberWithInt:c2.tag],
[NSNumber numberWithInt:c4.tag],
all the way to:
[NSNumber numberWithInt:h7.tag],nil];
for the part where you save the game
and:
a2.tag = [((NSNumber*)[savedGame objectAtIndex:0]) intValue];
all the way up to:
h7.tag = [((NSNumber*)[savedGame objectAtIndex:32]) intValue];
at the part where you resume your game. However, this code is apparently SO BAD that whenever it gets to this code in the ios simulator it crashes XCODE TOO(which gets very annoying because I need to force quit and start the program again)(its xcode 4)
Saved game is created in the .h like:
NSArray *savedGame;
I guess I will have to add something where it checks if there are 32 numbers in that second part--so if you could add that in your answer that would be great--and thanks in advance! I think the problem is with the second part of that code-- the
g2.tag = [((NSNumber*)[savedGame objectAtIndex:25]) intValue];
I have also heard of NS Mutable Arrays, so maybe that could solve my problem?
Thanks for any and all help!! And I am also open to new ways--maybe not arrays--that could solve this problem!! Thankyou in advance!!!

Use an NSMutableArray instead and you can do things like
[savedGame replaceObjectAtIndex:4 withObject:[NSNumber numberWithInt:a8.tag]];
You can also save these in NSUserDefaults:
NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults];
[prefs setInteger:a4.tag forKey#"a4.tag"];
a4.tag = [prefs integerForKey:#"a4.tag"];
This latter approach will also allow you to use a for loop to set and retrieve these values.

You should really use an NSDictionary for this job.
http://developer.apple.com/library/mac/#documentation/Cocoa/Reference/Foundation/Classes/NSDictionary_Class/Reference/Reference.html
This will allow you to query your data using keys.

If you are suspecting that you could be accessing your array beyond its size, then you could check if the array has got the number of objects you expect by inspecting [savedGames count].
Don't know if it helps.
As a general suggestion, I would first run your unmodified program in debugging mode (if you are not doing that already), and possibly step-by-step in the region where it fails. So you will know exactly which is the offending statement.
In order to further try and understand what is happening, I would split your assignments in multiple lines:
NSNumber* number = [savedGame objectAtIndex:0];
a2.tag = [number intValue];
if you set a breakpoint on the first statement you can see what objectAtIndex is returning.
Of course I understand it is big work to make all those changes.
As an alternative approach, since it seems to me that what matters to you are the ints (not the NSNumbers, you are using those only to store the ints somewhere), you could simply resort to using a C array of longs. This would avoid all the conversions back and forth. Of course, I am not sure whether you are really only interested in the ints.

Ummmm, based on the way your tags are situated, i guess its some kind of checkers like game? As in you have a 64 square grid but only half of the spaces are playable.
As for your comment about a mutable array, a mutable array just allows you to dynamically add or remove objects to the array. A regular NSArray has a fixed size and components (you cant add to it or remove from it). So you dont need to do the initWithObjects: part with a mutable array.
But, I really think you should restructure the way you are doing this. In this situation, you would want an object that has a location. Then you can just do
#interface GamePiece : NSObject
{
CGPoint location; //an object with an x and y
}
#property (assign, readwrite) CGPoint location;
-(void)saveTheGame {
[self setSavedGame:[[[NSMutableArray alloc] init] autorelease]];
for(GamePiece *piece in allPieces)
{
[savedGame addObject:piece]
}
}
Then in loadGame
if([savedGame count] == 32)
{
[self setAllPieces:nil]; //allPieces is an array object of a "Game" that contains
//references to all the pieces on the board
for(GamePiece *piece in savedGame)
{
[allPieces addObject:piece];
}
}

Related

Override the NSObject data

i have one array this array contain Question Objects so here i need to change the positions for array
Question *que=[[Question alloc]init];
que=[myarray objectAtIndex:1];
Question *que1=[[Question alloc]init];
que1=[myarray objectAtIndex:2];
here i need to inter change objects each other some
[que1 setValue: que.name forKey:#"Name"];
[myarray relplaceObjectAtIndex:2 withObject:que1];
is it right way to set value same objectValues
Please guide me hoe can inter change value.
Thanks for advance
There are significant issues with your code here:
This statement:
Question *que = [[Question alloc] init];
Allocates a new Question instance and assigns it to the variable que. When you do:
que = [myarray objectAtIndex:1];
You are overwriting the Question instance that you just allocated, effectively leaking memory (because you never released it). This won't be a problem if you are using ARC but nevertheless it is something to be mindful of because with or without ARC it is pointless. You did this twice, once for que and once for que1. Since you don't actually need to allocate and initialise a new Question instance, you can just do:
Question *que = [myarray objectAtIndex:1];
You obtain a reference to a Question object and assign it to que1. Then you mutate it and want to put it back into the array. This is pointless because the array already holds a reference to the same Question instance that you obtained with objectAtIndex:.
You haven't really explained what you are trying to do. Your entire code basically boils down to:
[[[myarray objectAtIndex:2] setValue:[[myarray objectAtIndex:1] name] forKey:#"Name"];
Your code should work how you intend with what you have shown. Just a few points to be aware of:
You need myarray to be an NSMutableArray
You have a typo here: relplaceObjectAtIndex:2 it should be replaceObjectAtIndex
Arrays start at index 0, which I'm sure you are aware of.
First use NSMutableArray object to hold it not NSArray
then.
you need to understand one main thing you are holding only a pointer to an object. array is managing it. You have created an object before accessing object inside array, dont do that it creates memory leak. You have to access the object from array only.
Question * que1=[myarray objectAtIndex:1];
[que1 retain];
[myarray removeObjectAtIndex:1];
Question * que2=[myarray objectAtIndex:2];
[que2 retain];
[myarray removeObjectAtIndex:2];
its possible you are not using ARC and your array is the only owner of the object. So If you remove object from array the it might release the whole object
[myarray insertObject:que2 atIndex:1];
[myarray insertObject:que1 atIndex:2];
this is a sample to put object in any position.
Read class references NSMutableArray

How to store NSTimeInterval values into a NSMutableArray?

I have a requirement where i have a Video that is played using MPMediaPlayerController. Along with the video i have two buttons where i need to capture the current playback time when the button are clicked and store all the relevant clicks individually. I am able to get the current playback time of the video using "currentPlaybackTime" property which returns NSTimeInterval. But can someone help me in how to store all the NSTimeInterval values into an NSMutableDictionary. I have tried the following ways:
-(void)onClickOfGood {
NSLog(#"The current playback time in good:%g",moviePlayerController.currentPlaybackTime);
currentPlaybackTime = moviePlayerController.currentPlaybackTime;
//NSArray *arrayContainsGoodClicks = [[NSArray alloc]initWithObjects:currentPlaybackTime, nil ];
NSNumber *goodTimeIntervals = [NSNumber numberWithDouble:currentPlaybackTime];
NSMutableArray *arrayContainsGoodClicks = [[NSMutableArray alloc]initWithObjects:goodTimeIntervals,nil ];
NSLog(#"The total count of Array is: %i",[arrayContainsGoodClicks count]);}
But everytime after the click of good button i am getting the Array count as only 1. Can someone please throw a light on where i am going wrong?
But everytime after the click of good button i am getting the Array count as only 1.
This is not surprising, considering that you are creating a brand-new NSMutableArray on the previous line.
To fix this, you need to make NSMutableArray *arrayContainsGoodClicks an instance variable (AKA ivar), initialize it to [NSMutableArray array] in your designated initializer, and then use
[arrayContainsGoodClicks addObject:goodTimeIntervals];
to add objects to the array.
If you are looking to use NSMutableDictionary instead, the strategy would be identical, except you would need to decide on an object that you would like to use as unique keys to your NSDictionary. Also remember that NSMutableDictionary is not ordered, so you might need to take care of sorting each time you display your dictionary items to users.
You need to create arrayContainsGoodClicks only once (in init method for example) and then add value to this array in your button handler:
//.h
NSMutableArray *arrayContainsGoodClicks;
//.m - init
arrayContainsGoodClicks = [NSMutableArray array];
//.m - button handler
[arrayContainsGoodClicks addObject:goodTimeIntervals];
You need to create your array and store it as a ivar.
#property (retain, nonatomic) NSMutableArray *clicksArray;
...
#synthesize clicksArray;
Now in your -init method create the array like..
self.clicksArray = [NSMutableArray array];
And add the object to the array each time so your -onClickOfGood would become something like...
...
[self.clicksArray addObject: goodTimeIntervals];
NSLog(#"The total count of Array is: %i",[self.clicksArray count]);

Memory management in objective-c

I have this code in one of my classes:
- (void) processArray
{
NSMutableArray* array = [self getArray];
. . .
[array release];
array = nil;
}
- (NSMutableArray*) getArray
{
//NO 1:
NSMutableArray* array = [[NSMutableArray alloc]init];
//NO 2:
NSMutableArray* array = [NSMutableArray array];
. . .
return array;
}
NO 1: I create an array and return it. In the processArray method I release it.
NO 2: I get an array by simply calling array. As I'm not owner of this, I don't need to release it in the processArray method.
Which is the best alternative, NO 1 or NO 2? Or is there a better solution for this?
The method should return an autoreleased array, NO 2 is the better choice. The reason for this is that when you call the method with
NSMutableArray* array = [self getArray];
you will expect as a matter of convention to not have to release the array. If you want to take ownership of it, you retain it, but otherwise you shouldn't have to care about it. In Cocoa, you only take ownership by explicitly sending alloc or retain or copy (or new). Since the processArray method doesn't do that, it shouldn't have to take care of releasing the array.
So you should use NO 2, and also you should remove these two lines:
[array release];
array = nil;
If the array and its contents use a lot of memory or its used lots of times, you'll want to release them straight away, so use option 1. According to the Objective-C guidelines, you'll want to prefix the word "new" to your subroutine name instead of "get" in that case.
If on the other hand, you want to reduce the number of lines of code that say simply [array release]; or similar then use option 2.
It is simply a balance between reducing lines of code, and reducing unnecessary temporary memory use.
Whilst the autorelease pool will help in reducing memory leaks and make your code smaller, sometimes you need to explicitly release everything as it goes out of use to keep the use of memory down.
HTH
EDIT
Ah - I stand corrected. Reading the iPhone version of the Memory Management Programming Guide for Cocoa I see that the iPhone guidelines are to use a prefix of "new..." so for example "newArray" in this case, if the caller is supposed to manually release and NOT a prefix of "create...". "Creating" can refer either to creation of manually released or of automatically released objects and so would be ambiguous. Text corrected above.
- (void) processArray
{
NSMutableArray* array = [[self getArray] retain];
//Now you are the owner of array, so you take care to release it
. . .
[array release];
array = nil;
}
- (NSMutableArray*) getArray
{
//create a new array
//temporarily the method owns the array
NSMutableArray* array = [[NSMutableArray alloc]init];
//fill in here with elements or what you want
..........
[array autorelease];
//autorelease here says "I don't own the result
//if anyone cares about it, he should retain it himself
return array;
}
So in short when you create new objects you should autorelease them before returning.
Because if the calling method wants to use the result, the calling method should take care
of retaining and releasing the result.
It's always good to run the Klang static analyzer for this issues, when you are not really sure in your retaining/releasing code : http://clang-analyzer.llvm.org/

NSMutableArray. What is the fastest way to convert it to a plain ole C-array

I like the convenience of NSMutableArray but sometimes you just need to drop down to good ole C-arrays. Like when you are feeding interleaved vertex arrays to OpenGL.
What is the fastest way of copying the contents of an NSMutableArray to a C-array?
Yah, I realize this bit shuffling introduces inefficiency but I'd like to see if I can sneak by with this approach without taking a hit in frame rate.
Cheers,
Doug
from cocoabuilder mailing list
id *buffer = malloc(numberOf_ItemsIWant_ToFetch * sizeof(id));
[myArray getObjects:buffer range:rangeOfItems]
See -[NSArray getObjects:]. Just give it a buffer of the appropriate size and NSArray will fill the buffer with its contents. NSMutableArray is a subclass of NSArray, so it responds to all the same methods.
NSMutableArray *arrayOfThings;
Element elements[arrayOfThings.count+1];
for (int i=0;i<arrayOfThings.count;i++)
{
elements[i] = [arrayOfThings objectAtIndex:i];
}
Or something similar. I don't see any easy way to do this in the Apple docs.
int i=0;
foreach(YourClass *obj in array)
{
carray[i++] = [obj yourMethodToConvertToCType];
}

Using the value of a string to determine the instance of a class

I have a switch statement similar to this one:
switch (number)
{
case 1:
if (imageView1.hidden == NO)
{
imageView1.hidden = YES;
} else
{
imageView1.hidden = NO;
}
break;
case 2:
if (imageView2.hidden == NO)
{
imageView2.hidden = YES;
} else
{
imageView2.hidden = NO;
}
break;
And so forth and so on.
My question is how do I use a string with a value say "imageView1" and use that to access the instance of my imageView class instead of having a different case for each instance of imageView? I know it muse be similar to creating an NSPath from a string or something like that, but I'm just not sure where to look or what it would be called.
Thanks in advance for any help!
I don't disagree with those who are concerned about the design, if this is actually the code. I will assume, however, that you are only posting a generalized version of your question. And since this is an important concept in Objective-C, so we should talk about it.
You can access an object's properties by name using Key Value coding, and the routine -valueWithKey:.
NSString *nameOfView = #"imageView1";
[[self valueForKey:nameOfView] setHidden:YES];
This will, in order, look for a method called -imageView1, an ivar named imageView1 and finally an ivar named _imageView1. This technique is very heavily used in Cocoa, and is important to understand. This is one of the many reasons we name things carefully, and yet another reason that we make accessors that handle memory management for us. Search the docs for "Key-Value Compliance" for more information.
Now for this specific case, I would tend towards something more like JimG's solution, using an NSArray of views, so I can loop through them and turn on or off the ones I want based on their index. But I can imagine a lot of cases where that wouldn't be appropriate, and KVC may be.
Why not put the instances in an NSArray and index into that?
NSArray *views = [NSArray arrayWithObjects: imageView1, imageView2, nil];
NSImageView *iview = [views objectAtIndex: number];
Also, you could consider something like:
iview.hidden = ! iview.hidden;
[Edit: missing asterisks, oops]