Overriding description method for NSObject - iphone

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.

Related

App crashes when getting Notes from AddressBook iphone

Here is my code to get Notes from AddressBook.
+(NSString*)getNote:(ABRecordRef)record {
return ABRecordCopyValue(record, kABPersonNoteProperty);
}
But in above implementation I have memory leak. So to remove memory leak I wrote following code
+(NSString*)getNote:(ABRecordRef)record {
NSString *tempNotes = (NSString*)ABRecordCopyValue(record, kABPersonNoteProperty);
NSString *notes = [NSString stringWithString:tempNotes];
[tempNotes release];
return notes;
}
If I write above code my app crashes. Whats going wrong? Thanks.
UPDATE: I call this method as follows :
notes = [AddreesBook getNote:record];
where notes is my ivar & I am releasing it in dealloc method.
Your first implementation violates the ownership rule:
Memory Management Rules
Which is to say, the API call you're using contains "Copy", but you're treating it like an autoreleased object.
Given that you're returning an autoreleased object in your revised implementation, I suspect you're not retaining your returned note string. You'll be able to tell for sure if this is the case if when running under a debugger your app crashes in NSPopAutoreleasePool().
A simple test would be to send -retain to the note object you get back and see if the crash goes away:
NSString *note = [ MyAddressBook getNote: abRecord ];
[ note retain ];
/* ... use note ... */
/* we retained the object, we must also release it when done with it. */
[ note release ];
Assuming the record parameter is correctly set, the following should return an autoreleased NSString.
+ (NSString *)getNote:(ABRecordRef)record {
return [(NSString *)ABRecordCopyValue(record, kABPersonNoteProperty) autorelease];
}
However, I'm not currently seeing why your current version of getNote isn't working.

instruments showing NSPlaceholderstring leaks

I'm trying to reduce the memory leaks in my app, so i used instruments to find all the leaks. I managed to remove almost all of the leaks, except a very annoying one.
Instruments is telling me that i have a lot of NSPlaceholderstring leaks.
The code that generated the leak (according to instruments) is:
if (nil == storedHash)
{
NSString *description = [[NSString alloc] initWithFormat:#"1 = %# 2= %d", uId, service];
self.storedHash = description; // This line is the leak according to instruments
[description release];
description = nil;
}
return storedHash
storedHash is define like this:
#property(copy) NSString* storedHash;
I tried everything i can think of:
I used retain instead of copy
I used an autorelease allocation of the NSString (stringWithFormat)
I tried wrapping the code with an autorelease pool
Nothing of the above changed the leak. (In some cases the type of the leaks change, but there are still leaks)
Ideas anyone?
Where do you release storedHash? Do you release it in dealloc?
Note that NSPlaceholdeString is an implementation detail; it is the class of the instance returned by NSString's +alloc method.
How about in the dealloc method? Did you release the storedHash in the dealloc method? And how about checking if (nil == self.storedHash)
You should use
#property(nonatomic, retain) NSString* storedHash;
instead copy. #property(copy) didn't release your old NSObject and you should do it yourself:
if (nil == storedHash)
{
NSString *description = [[NSString alloc] initWithFormat:#"1 = %# 2= %d", uId, service];
[self.storedHash release];
self.storedHash = description; // This line is the leak according to instruments
[description release];
// description = nil; // it's unnecessary
}
also you should release storedHash in dealloc.

[NSCFString stringValue]: unrecognized selector sent to instance

I'm using this code to query core data and return the value of key, I store the value like this :
NSString *newName= #"test";
[newShot setValue:newName forKey:#"shotNumber"];
and I query like this :
NSManagedObject *mo = [items objectAtIndex:0]; // assuming that array is not empty
NSString *value = [[mo valueForKey:#"shotNumber"] stringValue];
NSLog(#"Value : %#",value);
I'm crashing with this message though :
[NSCFString stringValue]: unrecognized selector sent to instance,
does anyone know where that would be coming from ?
newName (#"test") is already an NSString. There is no need to call -stringValue to convert it to a string.
NSString *value = [mo valueForKey:#"shotNumber"];
I often times add a category for NSString to handle this:
#interface NSString(JB)
-(NSString *) stringValue;
#end
#implementation NSString(JB)
-(NSString *) stringValue {
return self;
}
#end
You can add a similar category to other classes that you want to respond this way.
[mo valueForKey: #"shotNumber"] is returning a string and NSString (of which NSCFString is an implementation detail) do not implement a stringValue method.
Given that NSNumber does implement stringValue, I'd bet you put an NSString into mo when you thought you were putting in an NSNumber.
The value for the key #"shotNumber" is probably of type NSString which is just a wrapper for NSCFString. What you need to do, is, instead of stringValue, use the description method.
Note that you could also get this problem if you are trying to access a string property on an object that you think is something else, but is actually a string.
In my case I thought my Hydration object was in fact a hydration, but checking its class via isKindOfClass I found that it was an NSString and realized that I had incorrectly cast it as a Hydration object and that my problem lied further up the chain.

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.)