why element over released in array in nslog statement - iphone

My app crashed when run to NSLog(#"...") statement, and the log on console showed an object was double freed. I used zombie instrument to check it, and got that one of strings in myAreas was over released. But I cannot understand why it happened? Any help? Thank you.
NSString *myArea = #"Europe";
NSArray *myTimeZones = [NSTimeZone knownTimeZoneNames];
NSMutableArray *myAreas = [NSMutableArray arrayWithCapacity:1];
[myTimeZones enumerateObjectsWithOptions:NSEnumerationConcurrent usingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
NSString *name = (NSString *)obj;
if ([name hasPrefix:myArea]) {
NSString *tmpArea = [name substringFromIndex:myArea.length+1];
[myAreas addObject:tmpArea];
}
}];
NSLog(#"My Cities in %# time zone: %#", myArea, myAreas);

NSMutableArray is not thread safe, thus it can lead to subtle bugs when used in different threads, drop NSEnumerationConcurrent and it should work fine.

Related

Core Data table to NSArray

I have the following Array which retrieved from the Core Data :
NSArray *dataArray = [context executeFetchRequest:request error:&error];
so I wrote this code to get each row data individually to send it to REST API:
for (NSString *str in dataArray) {
NSString *name =[dataArray valueForKey:#"name"];
NSString *dob = [dataArray valueForKey:#"dob"];
int gender =[[dataArray valueForKey:#"gender"]integerValue];
NSString *childId =[dataArray valueForKey:#"id"];
int response = [network sendName:name withDateOfBirth:dob andGender:gender forID:childId];
if (response == 200) {
// [self performSelectorOnMainThread:#selector(postSuccess) withObject:nil waitUntilDone:YES];
NSLog(#"Success");
}
}
but it's not working, because I couldn't know how data is stored in each index in the array!!
Please help, and if I am not doing this correctly please tell me a better way to do it.
Thanks.
NSString *name =[dataArray valueForKey:#"name"];
This doesn't do what you think it'll do. valueForKey:, when sent to an array, returns an array of the values corresponding to the given key for all the items in the array. So, that line will assign an array of the "name" values for all the items in dataArray despite the fact that you declared name as a NSString. Same goes for the subsequent lines.
What you probably want instead is:
for (NSManagedObject *item in dataArray) {
NSString *name = [item valueForKey:#"name"];
...
Better, if you have a NSManagedObject subclass -- let's call it Person representing the entity you're requesting, you can say:
for (Person *person in dataArray) {
NSString *name = person.name;
...
which leads to an even simpler version:
for (Person *person in dataArray) {
int response = [network sendName:person.name
withDateOfBirth:person.dob
andGender:person.gender
forID:person.id];
although I'd change the name of that method to leave out the conjunctions and prepositions. -sendName:dateOfBirth:gender:id: is enough, you don't need the "with", "and", and "for."

Memory leak in iphone App when analyzed

I'm getting a memory leak signal like the one shown in
how can i clear this, please help me .
Use (__bridge_transfer NSString *) instead of (__bridge NSString *)
With ARC, you can use __bridge_transfer to transfer memory management of the returned string to ARC
Example:
NSString *myString = [self encodeURL:#"hi*)"];
NSLog(#"%#",myString);
-(NSString *)encodeURL:(NSString *)string{
NSString *newString = #"";
newString = (__bridge_transfer NSString *)CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault, (__bridge CFStringRef)string, NULL, CFSTR("^%*)*&%$"),CFStringConvertNSStringEncodingToEncoding(NSUTF8StringEncoding));
return newString;
}
Try this...
NSString *newString = nil;
CFStringRef stringRef = CFURLCreateStringByAddingPercentEscapes(...);
newString = (NSString *)stringRef;
CFRelease(stringRef);
if(newString)
return newString;
Use
return [newString autorelease];
The NSString object newString is got allocated in the function CFURLCreateStringByAddingPercentEscapes.
so the object attaining the retain count of one at this moment. So when you are retuning the retained object you got memory leak signal. We can add the object newString to the autorelease pool so that the os will take care of the memory to release at the right time.
Hope this helps.

Crashes on this line

NSArray *listItems = [temp componentsSeparatedByString:#","];
Can anyone please tell me why?
temp is an NSString
Here's the entire code
- (NSString *)getStreetAddress
{
NSString* temp = [addressArray objectAtIndex:0];
if (temp != nil) {
NSArray *listItems = [temp componentsSeparatedByString:#","];
temp = [listItems objectAtIndex:0];
}
return temp;
}
EXC_BAD_ACCESS is the error
If execution gets to the line you say, en the most likely problem is that the first item in addressArray has been improperly deallocated while still part of the array. Since the array doesn't check to make sure the object it contains is valid, it will return a pointer to free memory. When you try to access this memory, it crashes. You can try running with NSZombiesEnabled=YES in the environment. If I am correct, you will get a error message logged to the console.

TableView UISearchBar on Tab Bar Controller Crashes while Searching

I've been playing around with a search facility for my application table view for a while now trying to get it working but i keep getting the same error in my console.
Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: ' [NSCFDictionary rangeOfString:options:]: unrecognized selector sent to instance
I believe that this following section may be the problem I have tried passing some NSLog entries inside the if statement and it seems to get through it but the problem is when I click on the search bar and starting typing, the first letter I type calls the error and cancels my app.
Here is where the problem is
In View Will Appear "Food" Array is initialized as below:
NSString *myDBnew =#"/Users/taxsmart/Documents/rw3app.sql";
database = [[Sqlite alloc] init];
[database open:myDBnew];
NSString *quer = [NSString stringWithFormat:#"Select category from foodcat"];
Food = [database executeQuery:quer];
//[database executeNonQuery:quer];
[database close];
Search bar delegate method where error is encountered:
(void) searchTableView
{
NSString *searchText = searchBar.text;
NSMutableArray *searchArray = [[NSMutableArray alloc] init];
// [searchArray addObjectsFromArray:Food];
for(NSDictionary *dictionary in Food)
{
NSString temp1 = [dictionary objectForKey:#"category"];
[searchArray addObject:temp1];
}
for (NSString *sTemp in searchArray)
{
NSLog(#"Value: %#",NSStringFromClass([sTemp class]));
NSRange titleResultsRange = [sTemp rangeOfString:searchText options:NSCaseInsensitiveSearch];
if (titleResultsRange.length > 0)
[copyListOfItems addObject:sTemp];
}
[searchArray release];
searchArray = nil;
}
What should I do?
Please Help.
Please Suggest
Thanks
It looks that result of database query (Food) is dictionary that contains dictionary. This code:
for(NSDictionary *dictionary in Food)
{
NSString temp1 = [dictionary objectForKey:#"category"];
[searchArray addObject:temp1];
}
can be replaced with:
for(NSDictionary *dictionary in Food)
{
NSObject *ob = [dictionary objectForKey:#"category"];
if([ob isKindOfClass: [NSString class]])
{
[searchArray addObject:ob];
}
else if([ob isKindOfClass: [NSDictionary class]])
{
NSDictonary *dic1 = (NSDictionary*)ob;
// ... at this point you can get the string for desired dictionary key
// or you can ignore it
}
}
With this code we can be sure that only strings are put into searchArray.
If you want to make full tree parsing for desired key 'category' then you should make some recursive function to search the dictionary.
You can dump Food variable to console to see at which leaf is actually the result you are looking for. Put the break-point and into console type 'po Food'.
Appears that there is an NSDictionary in your dataArray.
Add an
NSLog(#"%#",NSStringFromClass([description class]]));
To see which classes your dataArray contains.

What is causing memory leaks?

What is causing the leaks in this code? I really cannot understand it.
On thes lines:
1: NSMutableArray * days = [[NSMutableArray alloc]init];
2: [dic setObject:days forKey:key];
3: [days addObject:value];
The whole method:
-(void) addValueToDictionary: (NSMutableDictionary *) dic withValue: (NSNumber *) value forKey: (NSString *) key {
NSMutableArray * days = [dic objectForKey:key];
if (days == nil) {
NSMutableArray * days = [[NSMutableArray alloc]init];
[days addObject:value];
[dic setObject:days forKey:key];
[days release];
days = nil;
}
else {
[days addObject:value];
}
}
BR
//Christoffer
Check to make sure that dic is released. You should NSLog retainCount before where you think the final releases are and make sure they are 1 right before the final release.
Also, run a Build and Analyze to make sure you are releasing correctly. The built in Build and Analyze doesn't find as many leaks as running scan-build with all checks, so look into installing scan-build into Xcode as well.
Using an external Xcode Clang Static Analyzer binary, with additional checks
You should be getting a warning about re-declaring days. This may be throwing the leak check off if you are using the static analyser. Modified method below. Mostly coding style changes with a little defensive coding added.
-(void) addValueToDictionary: (NSMutableDictionary *) dic withValue: (NSNumber *) value forKey: (NSString *) key
{
if (nil == dic || nil == key || nil == value) return; // bail out on nil parameters
if (![dic objectForKey:key]) {
NSMutableArray * days = [[NSMutableArray alloc] init];
[dic setObject:days forKey:key];
[days release];
}
[[dic objectForKey:key] addObject:value];
}
Have you tried to change the name of the variable NSMutableArray *days within the if? Don't you get a warning because of that?
There's nothing wrong with that particular piece of code (other than the slightly questionable redefinition of days in the inner scope). Somewhere else you are retaining but forgetting to release the object you put in the dictionary.
change NSMutableArray initialization to...
NSMutableArray * days = [NSMutableArray array];