GKScore properties warning - iphone

I'm building a custom display for Game Center, which works, except I'm getting a warning for the following code -
NSMutableArray *playerIDsArray = [[NSMutableArray alloc] init];
[highScores removeAllObjects];
for (GKScore *thisScore in scores)
{
NSMutableDictionary *thisEntry = [[NSMutableDictionary alloc] init];
NSString *playerID = [thisScore playerID];
[thisEntry setObject:playerID forKey:#"playerID"];
[playerIDsArray addObject:playerID];
[thisEntry setObject:[NSNumber numberWithInt:(int)[thisScore value]] forKey:#"value"];
[highScores setObject:thisEntry forKey:[NSString stringWithFormat:#"%i",[thisScore rank]]]; // warning here
[thisEntry release];
}
The warning for [thisScore rank] says "Method '-rank' not found (return type defaults to 'id')". The code works fine, however. I must be missing something...
Any help appreciated!

in GKScore, rank is a NSInteger aka Object...
Where as calling %i is calling integer..
hence.. You must call [[thisScore rank]intValue] to get the integer Value of the NSInteger Object..

Finally figured it out - bit daft really, I just hadn't included this -
#import <GameKit/GKScore.h>
I'd just assumed it was covered by importing the other Game Center headers... Thanks anyway!

Related

Releasing Object is it necessary?

I am stuck in the middle of memory management stuff. Please help me out in solving my question.
NSMutableArray *array = [[NSMutableArray alloc]init];
Object *obj = [[Object alloc]init];
[array addObject: obj];
[obj release];
Is it necessary to release obj in above code?
The answer to your question is: yes, if you don't use ARC. If you are writing a new app, you should seriously consider using ARC.
Container objects in Objective-C always balance their retain/release count. In other words, you should always manage memory as if you did not add the object and make sure your own code balances its retain count. Note that this is a convention and is not enforced, but you could always trust the built-in classes to follow this convention. Also, you can perform a static analysis (Cmd+Shift+B in XCode) to detect these problems. It would have pinpointed this in your code above.
The correct code in the case above would be:
NSMutableArray *array = [[NSMutableArray alloc]init];
Object *obj = [[[Object alloc]init]autorelease];
[array addObject: obj];
or
NSMutableArray *array = [[NSMutableArray alloc]init];
Object *obj = [[Object alloc]init];
[array addObject: obj];
[obj release];
since NSMutableArray (and its cousins) will retain the object as long as it is in the collection.

Call class method from another class?

I realize this question is pretty basic, but I'm really stuck. I have a plist. I'm trying to read that into an array so I can work with it in various classes. So in one class I have:
+ (NSArray*)questionArray
{
static NSArray* questions = nil;
if(!questions)
{
NSString *path = [[NSBundle mainBundle] pathForResource:#"Questions" ofType:#"plist"];
NSDictionary *dic = [[NSDictionary alloc] initWithContentsOfFile:path];
NSArray *questionsArray = [dic objectForKey:#"groups"];
NSMutableArray *questionObjects = [[NSMutableArray alloc] initWithCapacity: [questionsArray count]];
for(NSDictionary* questionDic in questionsArray)
{
QuestionContainerObject* object = [[self alloc] initWithDictionary:questionDic];
[questionObjects addObject:object];
[object release];
}
questions = questionObjects;
[dic release];
}
return questions;
}
I want to be able to access the things I pull out of the array from another class. I tried calling it like NSString *str = [QuestionContainerObject questionArray]; from my other class (after importing the header) but I get the 'class method +questionArray not found' warning.
Can someone please point me in the right direction? I'm really lost! Thanks!!
The warning is because the compiler does not know the questionArray method exists.
define this method in the header (QuestionContainerObject.h)
#interface QuestionContainerObject
+ (NSArray*)questionArray;
#end
and in the file using it:
#import QuestionContainerObject.h
Also remember to release objects created using [class alloc]
Did you put the class method declaration in the header file?
Btw, move the static NSArray* questions = nil; outside of the method body and remove the = nil, or else its not going to have the effect you wanted, i think.

NSMutableArray's count method causes a bad access error?

I see a few similar questions, but no simple answers. I'm just playing around with NSMutableArray's to get a feel for them before I actually use them in my real project. For some reason, it's giving me an EXC_BAD_ACCESS error when I try to call count on the array, and I can't figure out why.
- (void) applicationDidFinishLaunching:(UIApplication*)application
{
// Create window and make key
_window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
[_window makeKeyAndVisible];
NSMutableArray* test = [[NSMutableArray alloc] initWithObjects:[NSString stringWithFormat:#"first!"], [NSString stringWithFormat:#"second!"], nil];
[test insertObject:[NSString stringWithFormat:#"inserted"] atIndex:0];
NSLog(#"%#", [test objectAtIndex:0]);
NSLog(#"%#", [test objectAtIndex:1]);
NSLog(#"%#", [test objectAtIndex:2]);
NSLog(#"%#", [test count]); //bad access here
}
All the inserting and accessing EXCEPT the count method work just fine. I don't see why this isn't working, and would greatly appreciate some help. Thanks!
The %# format specifier prints objects. The return value of -count is just an unsigned integer. You should use the format specifier %u for that type.
The problem is that [test count] returns an NSUInteger not a pointer (to an NSObject). Try this instead:
NSLog(#"%u", [test count]);
Note that using %d also works, but %u is preferred.
- (NSUInteger)count; returns an NSUInteger.
Use this instead:
NSLog(#"%u", [test count]); //bad access here
count is working just fine. It does however return a NSUInteger primitive and not a pointer to a NSObject subclass. The %# string formatter expects a point to an object and logs the NSString returned from that object's -description method. When you pass it a NSUInteger NSLog assumes it to be an object pointer and dutifully tries to send a -description message to memory address 3 which causes that EXEC_BAD_ACCESS.

How to add an object to the end of an NSMutableArray

I have the following code
NSMutableArray *plistArray = [[NSMutableArray alloc] initWithContentsOfFile:filepath];
[plistArray insertObject:title atIndex:2];
but would like to rather add the object to the end of the array.
How can this be done, and do I need to set the last value to nil, at the moment I dont and it works fine.
Regards
[plistArray addObject:title];
See the NSMutableArray Class Reference.

Creating Objects & Setting iVars in a Loop?

NSArray *planetArray = [NSArray arrayWithObjects:#"Earth",
#"Jupiter",
#"Saturn",
#"Neptune",
#"Pluto", nil];
NSMutableArray *objectArray = [[NSMutableArray alloc] init];
for(NSString *eachPlanet in planetArray) {
Planet *newPlanet = [[Planet alloc] init];
[newPlanet setValue:eachPlanet forKey:#"name"];
[newPlanet setValue:#"TEST" forKey:#"type"];
[newPlanet setValue:[NSNumber numberWithInt:1234] forKey:#"mass"];
[objectArray addObject:newPlanet];
[newPlanet release];
}
for(Planet *displayEachPlanet in objectArray) {
NSLog(#"DATA: %#", displayEachPlanet);
}
[objectArray release];
I am curious if this is the best way to create an object and set an iVar for each item in an array. Basically I am:
Creating a Planet object
Setting the iVar (from the NSString array)
Adding the Planet object to an array.
Releasing the Planet object
Printing my Planet objects
Releasing the array
NB: I am just testing, this is not for anything, I was just curious ...
cheers Gary
Can't see anything drastically wrong about doing it that way. One suggestion would be to have an extended initialiser for your planet class, along the lines of:
-(Planet*) initWithName:(NSString*)name andType:(NSString*)type withMass:(int)mass;
And then create the planet with:
Planet *newPlanet = [[Planet alloc] initWithName:eachPlanet andType:#"Test" withMass:42];
Looks good to me. If all you are doing with the objects is printing something from them, you could probably do it in one loop with less initializing and such, but if thats just a test..it looks fine.