Syntax for Extracting CGFloat out of NSDictionary - iphone

Just wondering what the syntax would be to extract a CGFloat out of an NSDictionary like follows:
slider.minimumValue = [filterAttributes valueForKey:kCIAttributeSliderMin];

An NSDictionary only holds objects. What kind of object would wrap a primitive like CGFloat? NSNumber would make sense. Now, since CGFloat is either a float or a double, you'll probably want to get the double value to preserve precision/range.
Therefore:
slider.minimumValue = [[filterAttributes valueForKey:kCIAttributeSliderMin] doubleValue];

You can only put OBJECTS into an NSDictionary (or NSARRAY). CGFloat is a literal (just maps to a float), so you can't put it into or retrieve it from the dictionary.
Instead, wrap it as an NSNumber (when you add it to the dictionary), which is an object.
NSNumber *sliderMin = [NSNumber numberWithFloat:kCIAttributeSliderMin]
Or using the new syntax, you can just say #kCIAttributeSliderMin or #(kCIAttributeSliderMin) to autobox as an NSNumber.
To get the value back out, you'll retrieve the object as an NSNumber then say, [myNumber floatVal] to get the NSFloat.
Finally, you probably want to say "objectForKey" not "valueForKey".
update - sorry, in your example you're treating kCIAttributeSliderMin as a key, and I'm using it as the 'value'; but I think you get the point. Store an NSNumber object; retrieve an NSNumber object. Sorry for any confusion swapping that may have caused.

Related

Add GLKVector3 to an NSMutableArray

I am trying to add a GLKVector3 object into an NSMutableArray. I understand that NSMutableArrays will only accept certain objects so what would be the best way for me too add a GLKVector3 to an array.
Here is a sample of code:
for(id basenormal in [jsnmvtx objectForKey:#"baseNormals"]){
[basenormalsVectorArrays addObject:GLKVector3MakeWithArray(basenormal)];
}
Thanks
The issue is that GLKVector3 is a C-style struct, not an object. So it doesn't know how to respond to retain or release and therefore won't work with an NSArray.
What you can do is wrap each one into an NSValue as that's an object type and it knows how to keep arbitrary C types inside it. It's not especially neat because you're straddling the border between C and Objective-C but e.g.
GLKVector3 someVector;
[array addObject:[NSValue valueWithBytes:&someVector objCType:#encode(GLKVector3)]];
...
GLKVector3 storedVector;
NSValue *value = ... something fetched from array ...;
[value getValue:&storedVector];
// storedVector now has the value of someVector
That'll copythe contents of someVector into the NSValue and then copy them out again into storedVector.
You can use valueWithPointer: and pointerValue if you'd prefer to keep a reference to someVector in your array rather than copying contents, though then you'll need to be careful about manual memory management, so a better solution might be to use NSData as in:
// we'll need the vector to be on the heap, not the stack
GLKVector3 *someVector = (GLKVector3 *)malloc(sizeof(GLKVector3));
[array addObject:[NSData dataWithBytesNoCopy:someVector length:sizeof(GLKVector3) freeWhenDone:YES]];
// now the NSData object is responsible for freeing the vector whenever it ceases
// to exist; you needn't do any further manual management
...
GLKVector3 *storedVector = (GLKVector3 *)[value bytes];

CGFloat from a float?

How do you cast or create a CGFloat from a float?
I get a bad receiver type float * error.
CGFloat point = [graphValues objectAtIndex:0];
graphValues is probably not an NSArray, but a C-array of floats. If so, you want this:
CGFloat point = graphValues[0];
(The reason I think this is because it's telling you you're trying to call an Objective-C method on a float *.)
That's because the array is not an NSArray but a float array.
CGFloat point = graphValues[0];
If you want to know how CGFloat is declared, have a look in the header (it should be a double).

How to convert NSNumbers into integers from an NSArray(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];
}
}

Casting floats and UILabel

HI -
I have a value in a UILabel and I want to pass the number to a value that is of float type.
rate = float
hourlyRate = label
Below is my code and im getting errors. I know its bad form to go from object to primitive values but there has to be a way.
Any help would be appreciated!
rate = NSNumber numberWithFloat:[hourlyRate.text rate];
NSString has a convenient floatValue method:
rate = [hourlyRate.text floatValue];
rate = NSNumber numberWithFloat:[hourlyRate.text rate];
That’s invalid because if you’re trying to send the message numberWithFloat: to NSNumber it has to be enclosed in brackets, like so:
rate = [NSNumber numberWithFloat:[hourlyRate.text rate]];
And what’s more hourlyRate.text returns an NSString. You can’t send an NSString the method rate unless you subclassed it and added that method.
This is the right way to get the float value of UILabel, try this:
rate = [hourlyRate.text floatValue];
And do you mean:
float rate;

MKMapView centerCoordinate not returning proper values

In my app, I am saving coordinates from an MKMapView into a property list. After the user hits "save" I set the center coordinate of the selection view to that on the main view, and then save the mapView.centerCoodinate.latitude and longitude into a pList. However, this gives me a value like "1078114215" which the map says is not a vail coordinate. What am I doing wrong?
Saving a pointer instead of the two floats in the coordinate? Not saving as a float?
Sounds like you're accidentally mis-typing your double variable. When you add it to your dictionary to be stored as a plist be sure to transform it from a double to an NSNumber like this:
[myDictionary addObject:[NSNumber numberWithDouble:latitude] forKey:#"latitude"];
and when you retrieve it, transform it from an NSNumber to a double:
double latitude = [[myDictionary objectForKey:#"latitude"] doubleValue];