potential leak problems - objective-c

when I build and analize my application , am getting potential leak near the code [array1 release]...why its happening there..?thanks in advance
- (void) touchOnFeaturedCatalog
{
searchId == 2;
//featuredCatalogName = #"23064_Leeds2010";
//NSString *response = [ZoomCatalogAppDelegate getResponseFromServer:[NSString stringWithFormat:#"http://www.zoomcatalog.com/iphone/iphone.php?catalog=%#&iphone=Yes&pdf=No", featuredCatalogName]];
NSString *response = [ZoomCatalogAppDelegate getResponseFromServer:#"http://www.zoomcatalog.com/iphone/supplier.php"];
//NSString *response = [ZoomCatalogAppDelegate getResponseFromServer:#"http://test.atvescape.com/articles.php"];
//NSLog(#"Response = %#", response);
NSArray *array = [response componentsSeparatedByString:#"##"];
[array retain];
for(int i = 0; i < array.count; i++)
{
NSLog(#"Trying outer loop.... %d, %#, %#", i, [array objectAtIndex:i], featuredCatalogName);
NSArray *array4 = [featuredCatalogName componentsSeparatedByString:[array objectAtIndex:i]];
if(array4.count > 1)
{
response = [ZoomCatalogAppDelegate getResponseFromServer:[NSString stringWithFormat:#"http://www.zoomcatalog.com/iphone/catalog_search.php?tid2=%#&iphone=yes", [array objectAtIndex:i]]];
NSArray *array3= [response componentsSeparatedByString:#"<br>"];
//baseURL = [NSString stringWithFormat:#"%#", [array3 objectAtIndex:0]];
global_ContentString = [NSString stringWithFormat:#"%#", [array3 objectAtIndex:2]];//(searchId == 1 ? [array objectAtIndex:2] : ([array objectAtIndex: isLineNameSearch ? 2 : 1]))];
[global_ContentString retain];
// NSLog(#"baseURL = %#", global_ContentString);
NSArray *array1 = [global_ContentString componentsSeparatedByString:#"###"];
for(int j = 0; j < array1.count; j++)
{
NSArray *array2 = [[array1 objectAtIndex:j] componentsSeparatedByString:#"##"];
NSString *str = [NSString stringWithFormat:#"%#", [array2 objectAtIndex:0]];
str = [str stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
if ([str caseInsensitiveCompare:featuredCatalogName] == NSOrderedSame)
{
global_ContentString = [ZoomCatalogAppDelegate getResponseFromServer:[NSString stringWithFormat:#"http://www.zoomcatalog.com/iphone/iphone.php?catalog=%#&iphone=Yes&pdf=No", [array2 objectAtIndex:5]]];
baseURL = [NSString stringWithFormat:#"%#", [[global_ContentString componentsSeparatedByString:#"<br>"] objectAtIndex:0]];
//global_ContentString = [NSString stringWithFormat:#"%#", [[global_ContentString componentsSeparatedByString:#"<br>"] objectAtIndex:1]];
[global_ContentString retain];
[global_MainPageController presentModalViewController:global_FullPageController animated:YES];
//NSLog(#"$$$$$$$$$$$$$$$$$$$$$$ Catalog id = %# $$$$$$$$$$$$$$$$$$$$$$$$$$", [array2 objectAtIndex:5]);
//[array1 release];memory leak
return;
}
// NSLog(#"Trying inner loop.... %d, %#, %#", j, str, featuredCatalogName);
}
}
// if([[array objectAtIndex:i] com
}
[array release];
return;
}
sorry for all..

If you are only using an object locally (within the method in which it is created) you can autorelease it. Objects that are created or returned by convenience methods available until the end of the function call. Unless you need the objects elsewhere, I suggest ditching the retain calls. The rule of thumb is that whenever you call alloc, new, retain, or copy you mist release the object. However, if you use a convenience method, The returned object is autogenerate for you.
It seems that you call [global_ContentString retain]; but then fail to call a corresponding release.

Related

Memory leak while handling Foundation Object from NSJSONSerialization

I'm struggling to fix a memory leak in a helper function I have made. The helper function takes the result of
+ (id)JSONObjectWithData:(NSData *)data options:(NSJSONReadingOptions)opt error:(NSError * _Nullable *)error
and converts all the leaf elements into NSStrings if they are NSNumbers.
Here is the method:
-(NSArray *) stringisizeObjects:(NSArray *)inputArray{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSMutableArray *mutable = [[NSMutableArray alloc] initWithCapacity:[inputArray count]];
for (int i = 0; i < [inputArray count]; i++) {
NSArray *keys = [inputArray[i] allKeys];
NSMutableDictionary *addDictionary = [[NSMutableDictionary alloc] initWithCapacity:[keys count]];
for (int j = 0; j < [keys count]; j++) {
id theObject = [[inputArray[i] objectForKey:keys[j]]autorelease];
if ([theObject isKindOfClass:[NSNumber class]]) {
[addDictionary setObject:[theObject stringValue] forKey:keys[j]];
[theObject release];
}else if ([theObject isKindOfClass:[NSString class]]){
[addDictionary setObject:[inputArray[i] objectForKey:keys[j]] forKey:keys[j]];
}
}
[mutable addObject:addDictionary];
}
NSArray *returnArray = [mutable copy];
[mutable removeAllObjects];
[mutable release];
[pool drain];
return returnArray;
}
Here is how I get the input array.
id parsedThingy = [NSJSONSerialization JSONObjectWithData:resultJSONData options:1 error:&jsonDecodeError];
Before I can pass the result to my stringisize method I must ensure that I have an NSArray of NSDictionaries with matching keys.
NSArray *resultArray = [self stringisizeObjects:parsedThingy];
The X-Code memory leaks tool has pointed me to this method as the cause of my problem.
Instruments showing leaks
As you can see I have tried wrapping things in autorelease pools, autoreleasing and releasing. I just don't see any way forward here.
This is a non ARC project that runs 24/7.
Edit: I took the advice from Droppy and tried to re-write the method using mutableCopy. The leak is still there. At this point my only work around maybe to change the source of the JSON to send only strings. :(
-(NSArray *) stringisizeObjects2:(NSArray *)inputArray{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSMutableArray *mutableArray = [inputArray mutableCopy];
for (int i = 0; i < [mutableArray count]; i++) {
NSMutableDictionary *mutableDict = [mutableArray[i] mutableCopy];
NSArray *keys = [mutableDict allKeys];
for (int j = 0; j < [keys count]; j++) {
if ([[mutableDict objectForKey:keys[j]] isKindOfClass:[NSNumber class]]) {
NSString *stringValue = [[mutableDict objectForKey:keys[j]] stringValue];
[mutableDict removeObjectForKey:keys[j]];
[mutableDict setObject:stringValue forKey:keys[j]];
}
}
mutableArray[i] = [mutableDict copy];
[mutableDict release];
}
NSArray *returnArray = [mutableArray copy];
[mutableArray release];
[pool drain];
return returnArray;
}
problem:
addDictionary called alloc but not call release or autorelease
returnArray = [mutable copy]; // did increase retainCount +1, need autorelease here
id theObject = [inputArray[i] objectForKey:keys[j]]; // not need autorelease or release for object that You not own
add NSAutoreleasePool to top an bottom here just do nothing
solution:
-(NSArray *) stringisizeObjects:(NSArray *)inputArray{
NSMutableArray *mutable = [[NSMutableArray alloc] initWithCapacity:[inputArray count]];
for (int i = 0; i < [inputArray count]; i++) {
NSArray *keys = [inputArray[i] allKeys];
NSMutableDictionary *addDictionary = [[NSMutableDictionary alloc] initWithCapacity:[keys count]];
for (int j = 0; j < [keys count]; j++) {
id theObject = [inputArray[i] objectForKey:keys[j]]; // not need autorelease
if ([theObject isKindOfClass:[NSNumber class]]) {
[addDictionary setObject:[theObject stringValue] forKey:keys[j]];
//[theObject release]; // not need release value here
}else if ([theObject isKindOfClass:[NSString class]]){
[addDictionary setObject:[inputArray[i] objectForKey:keys[j]] forKey:keys[j]];
}
}
[mutable addObject:addDictionary];
[addDictionary release]; // release after not use
}
NSArray *returnArray = [[[NSArray alloc] initWithArray:mutable] autorelease]; // auto release for return value
[mutable removeAllObjects];
[mutable release];
return returnArray;
}

How to print the reverse of NSString in objective c without using componentsSeparatedByString method?

I want to make a method which gives reverse of string.suppose I pass a NSString "Welcome to Objective C" in method and that method return a reverse of string like "C Objective to Welcome" not "C evitcejbO ot emocleW" without the use of componentsSeparatedByString method.
Is it possible to do with Objective c..?
Please help.
You can enumerate strings by words.
NSString *string = #"Welcome to Objective-C!";
NSMutableArray *words = [NSMutableArray array];
[string enumerateLinguisticTagsInRange:NSMakeRange(0, [string length])
scheme:NSLinguisticTagSchemeTokenType
options:0
orthography:nil
usingBlock:^(NSString *tag, NSRange tokenRange, NSRange sentenceRange, BOOL *stop) {
[array addObject:[string substringWithRange:tokenRange]];
}];
NSMutableString *reverseString = [[NSMutableString alloc] init];
for (NSString *word in [words reverseObjectEnumerator]){
[reverse appendString:word];
}
NSLog(#"%#", reverseString);
This will print...
"!C-Objective to Welcome"
You can change the options to omit whitespaces and stuff...
I used below method for reversing string in iOS
- (NSString *)reverseString:(NSString *)stringToReverse
{
NSMutableString *reversedString = [NSMutableString stringWithCapacity:[stringToReverse length]];
[stringToReverse enumerateSubstringsInRange:NSMakeRange(0, [stringToReverse length])
options:(NSStringEnumerationReverse | NSStringEnumerationByComposedCharacterSequences)
usingBlock:^(NSString *substring, NSRange substringRange, NSRange enclosingRange, BOOL *stop) {
[reversedString appendString:substring];
}];
return reversedString;
}
Sorry I misread your question earlier. I did it using a series of loops, my answer is messier than Fogmeister but I wanted to give it a shot to see if I could do it.
NSString *str = #"This is a test";
NSMutableArray *array = [[NSMutableArray alloc] init];
for(int i = 0; i < [str length]; i++)
{
char sTest = [str characterAtIndex:i];
if(sTest == ' ')
{
[array addObject:[NSNumber numberWithInt:i]];
}
}
NSInteger iNext = [[array objectAtIndex:[array count]-1] integerValue];
iNext+=1;
if(iNext < [str length])
{
[array addObject:[NSNumber numberWithInt:iNext]];
}
NSMutableArray *wordArray = [[NSMutableArray alloc] init];
for(int i = 0; i < [array count]; i++)
{
if (i == 0)
{
int num = [[array objectAtIndex:i] integerValue];
NSString *s = [[str substringFromIndex:0] substringToIndex:num];
[wordArray addObject:s];
}
else if(i == [array count]-1)
{
int prev = [[array objectAtIndex:i-1] integerValue]+1;
int num = [str length];
NSString *s = [[str substringToIndex:num] substringFromIndex:prev];
[wordArray addObject:s];
}
else
{
int prev = [[array objectAtIndex:i-1] integerValue]+1;
int num = [[array objectAtIndex:i] integerValue];
NSString *s = [[str substringToIndex:num] substringFromIndex:prev];
[wordArray addObject:s];
}
}
NSMutableArray *reverseArray = [[NSMutableArray alloc]init];
for(int i = [wordArray count]-1; i >= 0; i--)
{
[reverseArray addObject:[wordArray objectAtIndex:i]];
}
NSLog(#"%#", reverseArray);
Here i have done with replacing character with minimal number of looping. log(n/2).
NSString *string=#"Happy World";
NSInteger lenth=[string length];
NSInteger halfLength=[string length]/2;
for(int i=0;i<halfLength;i++)
{
NSString *leftString=[NSString stringWithFormat:#"%c",[string characterAtIndex:i]];
NSString *rightString=[NSString stringWithFormat:#"%c",[string characterAtIndex:(lenth-i-1)]];
string= [string stringByReplacingCharactersInRange:NSMakeRange(i, 1) withString:rightString];
string=[string stringByReplacingCharactersInRange:NSMakeRange((lenth-i-1), 1) withString:leftString];
}
NSLog(#"%#",string);
Try This , It's working perfect as per your expectation ,
Call Function :-
[self reversedString:#"iOS"];
Revers String Function :-
-(void)reversedString :(NSString *)reversStr
{ // reversStr is "iOS"
NSMutableString *reversedString = [NSMutableString string];
NSInteger charIndex = [reversStr length];
while (charIndex > 0) {
charIndex--;
NSRange subStrRange = NSMakeRange(charIndex, 1);
[reversedString appendString:[reversStr substringWithRange:subStrRange]];
}
NSLog(#"%#", reversedString); // outputs "SOi"
}
Hope So this is help for some one .
There is no API to do that, if that's what you are asking.
You can always iterate through the string looking for white spaces (or punctuation, it depends on your needs), identify the words and recompose your "reversed" message manually.

Adding objects from array to dictionary

I am getting rows from a SQLite DB and trying to insert them into a dictionary. Except I keep getting errors! I get the error "Implicit conversion of an Objective-C pointer to 'const id *' is disallowed with ARC" Which I know means that I cant use a pointer when I am adding objects to my dictionary. So how do I go about fixing it so I can add those arrays to a dictionary?
NSArray *keyArray = [[NSMutableArray alloc] init ];
NSArray *valueArray = [[NSMutableArray alloc ] init ];
NSDictionary* dic;
NSInteger dataCount = sqlite3_data_count(statement);
while (sqlite3_step(statement) == SQLITE_ROW) {
#try {
for (int i = 0; i < dataCount; i ++)
{
NSString* key = [NSString stringWithUTF8String:(char *)sqlite3_column_text(statement, i)];
NSString *value = [NSString stringWithUTF8String:(char *)sqlite3_column_text(statement, i)];
if ([value length] == 0)
{
value = #"";
}
keyArray = [keyArray arrayByAddingObject:key];
valueArray = [valueArray arrayByAddingObject:value];
}
}
#catch (NSException *ex)
{
NSLog(#"%#,%#", [ex name], [ex reason]);
}
dic= [NSDictionary dictionaryWithObjects:valueArray forKeys:keyArray count:[keyArray count]];
The dictionaryWithObjects:forKeys:count: takes C-style arrays, not NSArray objects. The dictionaryWithObjects:forKeys: may do the trick, but you may be better off constructing a mutable dictionary as you go, bypassing NSArrays entirely.
NSDictionary* dic;
NSMutableDictionary *tmp = [NSMutableDictionary dictionary];
for (int i = 0; i < dataCount; i ++)
{
NSString* key = [NSString stringWithUTF8String:(char *)sqlite3_column_text(statement, i)];
NSString *value = [NSString stringWithUTF8String:(char *)sqlite3_column_text(statement, i)];
[tmp setObject:value forKey:key];
}
dict = tmp;
[dicBodyPost setValue:arrContactAddress forKey:#"contactAddress"];

Displaying an array in xcode

I am trying to display the an array with different factors of a number ("prime"). But instead of giving me the int numbers I always get 0,1,2,3,4,5,... .
factors.text = #"";
int factorsNumber;
NSMutableArray *array;
array = [NSMutableArray arrayWithCapacity:5];
for (factorsNumber=1; factorsNumber<=prime; factorsNumber++) {
if (prime%factorsNumber == 0) {
[array addObject:[NSString stringWithFormat:#"%d", factorsNumber]];
}
}
for (int i = 0; i < [array count]; i++) {
[array replaceObjectAtIndex:1 withObject:#"4"];
NSString *temp = [NSString stringWithFormat:#"%d, ", i, [[array objectAtIndex:i] intValue]];
factors.text = [factors.text stringByAppendingString:temp];
}
Replace
NSString *temp = [NSString stringWithFormat:#"%d, ", i, [[array objectAtIndex:i] intValue]];
with
NSString *temp = [NSString stringWithFormat:#"%d, ", [[array objectAtIndex:i] intValue]];
The problem was you were only printing the array index, not the value.

Extract a NSDictionary from a NSMutableArray

I need to extract a NSDictionary from a NSMutableArray, and extract an object from that dictionary.
The code should be quite easy, but I keep having a SIGABRT error on the NSDictionary declaration.
-(void)calcolaConto {
conto = [[NSNumber alloc] initWithDouble:0];
for (int i=0; [shoppingListItems count]; ++i) {
NSDictionary *dictVar = (NSDictionary *) [shoppingListItems objectAtIndex:i]; //<-- SIGABRT
NSNumber *IO = (NSNumber *) [dictVar objectForKey:#"incout"];
NSNumber *priceValue = (NSNumber *) [dictVar objectForKey:#"price"];
if ([IO isEqualToNumber:[NSNumber numberWithInt:0]]) {
conto = [NSNumber numberWithDouble:([conto doubleValue] + [priceValue doubleValue])];
} else if ([IO isEqualToNumber:[NSNumber numberWithInt:1]]) {
conto = [NSNumber numberWithDouble:([conto doubleValue] - [priceValue doubleValue])];
}
NSLog(#"Valore %#", conto);
}
}
"shoppingListItems" is created in this way:
NSMutableDictionary *rowDict = [[NSMutableDictionary alloc] initWithCapacity:6];
[rowDict setObject:primaryKeyValue forKey: ID];
[rowDict setObject:itemValue forKey: ITEM];
[rowDict setObject:priceValue forKey: PRICE];
[rowDict setObject:groupValue forKey: GROUP_ID];
[rowDict setObject:incOut forKey:INC_OUT];
[rowDict setObject:dateValue forKey: DATE_ADDED];
[shoppingListItems addObject: rowDict];
The problem is that your loop never stops. You should use:
for (NSUInteger i = 0; i < [shoppingListItems count]; i++) {
or:
for (NSDictionary* dictVar in shoppingListItems) {
so that you do not try to access an element that is out of bounds. In your
current loop i will be incremented until it reaches [shoppingListItems count]
which is beyond the end of the array, so objectAtIndex will throw an exception.