App crashing because of glGetString - iphone

I am running cocos2d-iphone 1.0.0 and following this tutorial to use cocos2d with ARC. Unfortunately, I am getting a 'SIGABRT' crash error whenever I try to add a TMX Tiled Map to a CCLayer. I have traced this problem down to the -(BOOL)checkForGLExtension:(NSString *)searchName, and even further to within this function to NSString *extensionsString = [NSString stringWithCString:glExtensions encoding: NSASCIIStringEncoding];
Here is the checkForGLExtension function:
- (BOOL) checkForGLExtension:(NSString *)searchName {
// For best results, extensionsNames should be stored in your renderer so that it does not
// need to be recreated on each invocation.
NSLog(#"%#", glExtensions);
NSString *extensionsString = [NSString stringWithCString:glExtensions encoding: NSASCIIStringEncoding];
NSLog(#"%#", extensionsString);
NSArray *extensionsNames = [extensionsString componentsSeparatedByString:#" "]; }
The encoding: part of NSString *extensionsString = [NSString stringWithCString:glExtensions encoding: NSASCIIStringEncoding];is probably making the application crash. I am also receiving NULL in my logs for GL_VENDOR, GL_VERSION, GL_RENDERER, and even glExtensions.
Looking back at gl.h in the OpenGLES.framework shows me this:
/* StringName */
#define GL_VENDOR 0x1F00
#define GL_RENDERER 0x1F01
#define GL_VERSION 0x1F02
#define GL_EXTENSIONS 0x1F03
In which all of them are NULL.

NOTE: I have no idea about iOS development :)
Getting NULL from glGetString usually means that the OpenGL context is not bound or was created incorrectly. You should check that. Also check for GL error with glGetError.

Related

Overriding description method for NSObject

I'm not sure if this is a simulator issue, but I don't remeber having this problem before when I was using the iPad 5.0 simulator and below (now I'm running iPad 5.1 simulator). I overrode the description method for my Condition object to be:
- (NSString *)description {
NSString *str = [[NSString alloc] initWithFormat:#"Condition: %#", _conditionName];
return [str autorelease];
}
I have an array of these objects. My values are all valid. When I do:
for (Condition *p in self.reportsArray) {
NSLog(#"%#", [p description]);
}
It logs all my values, and then it crashes at the end. When I look at Instruments with Zombies, the last 4 calls are
-[NSPlaceHolderString initWithBytes:length:encoding:]
+[NSString stringWithUTF8String:]
-[NSAutoreleasePool release]
-[NSPlaceholderString initWithFormat:locale:arguments:]
Am I overriding description correctly?
Edit:
In Instruments, I get: message was sent to a deallocated object (zombie) at address:0x8ccf190. On the app itself, I get EXC_BAD_ACCESS.
It seems like the string returned from your description method is being released too soon.
Try rewriting your method using the stringWithFormat: class method.
- (NSString *)description {
return [NSString stringWithFormat:#"Condition: %#", _conditionName];
}
Make sure _conditionName is not a primitive.
Because the format string "%#" expects an object.

uniqueIdentifier deprecated, example from Cocos2d

I have searched the web for the answer and have found quite a few solutions but have to admit i do not really understand, as i am pretty new, how to apply the answer, one example is: UIDevice uniqueIdentifier Deprecated - What To Do Now?
I would really appreciate if someone could show me an example how to apply the solution to the problem in the code below as the following line is deprecated (uniqueIdentifier), the code line is from Cocos2d CLScoreServerRequest.m but comes up in a few others as well:
device = [[UIDevice currentDevice] uniqueIdentifier];
The function looks like:
-(BOOL) requestScores:(tQueryType)type
limit:(int)limit
offset:(int)offset
flags:(tQueryFlags)flags
category:(NSString*)category
{
// create the request
[receivedData setLength:0];
// it's not a call for rank
reqRankOnly = NO;
NSString *device = #"";
if( flags & kQueryFlagByDevice )
device = [[UIDevice currentDevice] uniqueIdentifier];
// arguments:
// query: type of query
// limit: how many scores are being requested. Default is 25. Maximun is 100
// offset: offset of the scores
// flags: bring only country scores, world scores, etc.
// category: string user defined string used to filter
NSString *url= [NSString stringWithFormat:#"%#?gamename=%#&querytype=%d&offset=%d&limit=%d&flags=%d&category=%#&device=%#",
SCORE_SERVER_REQUEST_URL,
gameName,
type,
offset,
limit,
flags,
[category stringByAddingPercentEscapesUsingEncoding: NSUTF8StringEncoding],
device
];
// NSLog(#"%#", url);
NSURLRequest *request=[NSURLRequest requestWithURL:[NSURL URLWithString:url]
cachePolicy:NSURLRequestUseProtocolCachePolicy
timeoutInterval:10.0];
// create the connection with the request
// and start loading the data
self.connection=[NSURLConnection connectionWithRequest:request delegate:self];
if (! connection_)
return NO;
return YES;
}
Here's the quick and simple solution:
Change your project's (or target's) deployment target to iOS 4.x or lower. In that case the compiler will still issue a warning but it will be just a warning. Only if your deployment target it iOS 5.0 or newer will the compiler generate an error about the deprecated method.
As for the warnings within the Cocos2D source code, ignore those warnings until the next Cocos2D official release fixes that issue.
you could do:
CFUUIDRef uuidRef = CFUUIDCreate(kCFAllocatorDefault);
if(uuidRef)
{
device = (NSString *) CFUUIDCreateString(kCFAllocatorDefault, uuid);
CFRelease(uuidRef);
} else {
// it's almost 100% likely you won't end up here but
// you should still do something with device (like throw an alert or NSLog)
}
And I just noticed this answer can also be found in this related question.
B.T.W., this UUID will not persist (or be the same) if the app is uninstalled and reinstalled on a device. If you want something like that, you incorporate the code found at:
https://github.com/gekitz/UIDevice-with-UniqueIdentifier-for-iOS-5
Except in this case, there's apparently a tough license agreement.

iOS error errSecInteractionNotAllowed or –25308 on SecItemAdd

I wrote some code to test adding an item to a keychain. I am testing on iPad 4.2.1 (jailbroken). I signed the binary with ldid -S prog on iPad.
Code:
#import <Security/Security.h>
#import <Security/SecItem.h>
#import <Foundation/NSDictionary.h>
#import <Foundation/NSString.h>
#import <Foundation/NSObject.h>
#import <CoreFoundation/CoreFoundation.h>
#import <Foundation/NSAutoreleasePool.h>
#import <Foundation/NSKeyValueCoding.h>
int main(int argc, char *argv[])
{
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
NSDictionary *attributesToStore = [NSDictionary dictionaryWithObjectsAndKeys:
[#"testuser01" dataUsingEncoding:NSUTF8StringEncoding],kSecAttrAccount,
[#"test123" dataUsingEncoding:NSUTF8StringEncoding],kSecValueData,
kSecClassInternetPassword,kSecClass,
[#"www.example.com" dataUsingEncoding:NSUTF8StringEncoding],kSecAttrServer,
kCFBooleanTrue, kSecReturnPersistentRef,
[#"Sample password" dataUsingEncoding:NSUTF8StringEncoding], kSecAttrDescription,
[#"password label" dataUsingEncoding:NSUTF8StringEncoding],kSecAttrLabel, nil];
NSData *persistentRef = nil;
OSStatus result = SecItemAdd((CFDictionaryRef)attributesToStore, (CFTypeRef *)&persistentRef);
if (noErr == result)
{
NSLog(#"Added item to Keychain");
}
else {
NSLog(#"Item add failed");
NSLog(#"Result code: %d",result);
}
[pool release];
return 0;
}
The code compiles and links without any noise or warnings. But execution on the iPad throws an error -25308.
How do I troubleshoot this error?
I am pretty sure you need to set kSecClass key so the keychain knows what kind of item you are trying to add.
As a side note, I found the GenericKeychain sample code to be useful after I rewrote the init method as outlined in my answer to my question here.
The main problem with the example code is that many items are encoded as NSData objects where NSString objects should be used (kSecAttrAccount, kSecAttrLabel, kSecAttrDescription and kSecAttrServer). I'm surprised that this issue wouldn't result in an exception, although behavior on iOS may be different to Lion (where I looked at this).
It may also be that specifying kSecReturnRef instead of kSecReturnPersistentRef may be more appropriate (from the documentation, using kSecReturnPersistentRef vends "a persistent reference may be stored on disk or passed between processes"). It is a way to specify a keychain item for use with SecItemUpdate, SecItemDelete or SecItemCopyMatching using it with kSecMatchItemList that has the advantage of persistence between sessions (say using NSUserDefaults) or passing to another process. If the item is only used within the lifetime of the application, or it is more appropriate to find using other attributes, then the item reference using kSecReturnRef is likely more appropriate.

iPhone JSON object releasing itself?

I'm using the JSON Framework addon for iPhone's Objective-C to catch a JSON object that's an array of Dictionary-style objects via HTTP. Here's my connectionDidFinishLoading function:
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
[connection release];
NSString *responseString = [[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding];
[loadingIndicator stopAnimating];
NSArray *responseArray = [responseString JSONValue]; // Grab the JSON array of dictionaries
NSLog(#"Response Array: %#", responseArray);
if ([responseArray respondsToSelector:#selector(count)]) {
NSLog(#"Returned %# items", [responseArray count]);
}
[responseArray release];
[responseString release];
}
The issue is that the code is throwing a EXC_BAD_ACCESS error on the second NSLog line. The EXC_BAD_ACCESS error I think indicates that the variable got released from memory, but the first NSLog command works just fine (and shows that the data is all there); it seems that only when calling the count message is causing the error, but the respondsToSelector call at least thinks that the responseArray should be able to respond to that message. When running with the debugger, it crashes on that second line, but the stack shows that the responseArray object is still defined, and has 12 objects in it (so the debugger at least is able to get an accurate count of the contents of that variable).
Is this a problem with the JSON framework's creation of that NSArray, or is there something wrong with my code?
count returns an NSUInteger, not an object. Per the Apple Documentation you should use %lu and cast to unsigned long in this case instead to display it:
NSLog(#"Returned %lu items", (unsigned long)[responseArray count]);
With %#, NSLog() tries to interpret the value as a pointer to an object and to send a description message to it.
It is highly unlikely that there is accidentally a valid object at that memory location, so the code is bound to fail badly or show unpredictable results.
In addition to what gf and Nikilai said, [responseArray release]; over releases
If those guys got their method naming right, NSArray *responseArray = [responseString JSONValue]; returns an autoreleased instance.
Simple typo: Your format string in the second NSLog contains an %# instead of %d.

NSString potential leak

When I build and analyze my project on XCode, I obtain a 'warning' on the following line:
NSString *contactEmail = (NSString *)ABMultiValueCopyValueAtIndex(emailInfo, 0);
The message is: Potential leak on object allocated on line ... and stored into contactEmail.
Is there any error on that line?
UPDATE
I get the same 'warning' with this line of code:
ABMultiValueRef emailInfo = ABRecordCopyValue(person, kABPersonEmailProperty);
But here, I can't do this:
[emailInfo release];
I'm developing for iPhone.
ABMultiValueCopyValueAtIndex is a "Copy" function, which follows the "Create Rule". You need to call CFRelease to release it after finish using it.
NSString *contactEmail = (NSString *)ABMultiValueCopyValueAtIndex(emailInfo, 0);
...
if (contactEmail != nil)
CFRelease((CFTypeRef) contactEmail);
The cast is somewhat pointless.
The line might leak, unless you release or autorelease it somewhere.
Edit: For brevity:
NSString *contactEmail = [(NSString *)ABMultiValueCopyValueAtIndex(emailInfo, 0) autorelease];
(The cast might still be pointless, I'm unsure as to how the compiler would handle trying sending a message directly to a CFTypeRef.)