NSString crash when release - iphone

I use NSString to append strings, but when I release the "cacheStr" NSString, the iphone simulator crash.
Where should I put the release code ?
init code : I use three NSString to append content of the dataArray.
NSMutableArray *dataArray = [[NSMutableArray alloc] init];
NSString *cacheStr = [[NSString alloc] init];
NSString *tmpStr = [[NSString alloc] init];
NSString *notiyStr = [[NSString alloc] initWithFormat:#"This is a test message!"];
dataArray = [NSArray arrayWithObjects:
#"currency1.png",
#"currency2.png",
#"currency3.png",
#"currency4.png",
#"currency5.png",
#"xxxxxx",
#"currency1.png",
#"currency2.png",
#"currency3.png",
#"currency4.png",
#"currency5.png",
#"xxxxxx",
nil];
append string code : use for loop to append strings.
int isFailed = 0;
int countOfDataArray = [dataArray count];
if (!isFailed) {
for (int i=0; i < countOfDataArray; i++) {
if ([[dataArray objectAtIndex:i] isEqualToString:#"xxxxxx"]) {
tmpStr = [cacheStr stringByAppendingFormat:#"%#\n", [dataArray objectAtIndex:i]];
}
else {
tmpStr = [cacheStr stringByAppendingFormat:#"value %d : %#\n", i+1, [dataArray objectAtIndex:i]];
}
cacheStr = [tmpStr copy];
[tmpStr release];
}
}
tmpStr = [notiyStr stringByAppendingString:cacheStr];
release code : when I add [cacheStr release], the simulator will crash...
[dataArray release];
[notiyStr release];
// [cacheStr release]; /* crash ... */
Thanks!

its more simple to declare a NSString like this
NSString *tmpStr = #"This is a test message!";
then no need to release it,when you dont use alloc

This
NSMutableArray *dataArray = [[NSMutableArray alloc] init];
dataArray = [NSArray arrayWithObjects:
#"currency1.png",
#"currency2.png",
#"currency3.png",
#"currency4.png",
#"currency5.png",
#"xxxxxx",
#"currency1.png",
#"currency2.png",
#"currency3.png",
#"currency4.png",
#"currency5.png",
#"xxxxxx",
nil];
is strange! You are allocating a mutable array and assigning the pointer pointing to that array to an array which you do not own. It is probably already (auto)released when you try to use it. Therefore int countOfDataArray = [dataArray count]; will result in countOfDataArray being zero. Therefore cacheStr is never set. Still it shouldn't crash on releasing the cacheStr.
Change it to:
NSMutableArray *dataArray = [[NSMutableArray alloc] initWithObjects: #"currency1.png",
#"currency2.png",
#"currency3.png",
#"currency4.png",
#"currency5.png",
#"xxxxxx",
#"currency1.png",
#"currency2.png",
#"currency3.png",
#"currency4.png",
#"currency5.png",
#"xxxxxx",
nil];
and you should be fine.

dont use [NSString alloc] init. To use NSString value=#"Message"; No need to release it.

Related

Initialize multiple objects with different name

How can I Initialize and allocate multiple objects with different name and pass it to the NSArray. from Below code the object is initialized once in loop and I need to initialized multiple times as per the For loop will go with different name..and then pass it to NSArray.please check the code below..
when For loop will start means i=0 ..initialized item would betempItemi
now next time when i=1 and i=2 the tempItemi name will be same .how can i change this with in loop..and pass it to NSArray *items
for (int i = 0; i< [Array count]; i++)
{
id object = [Array objectAtIndex:i];
if ([object isKindOfClass:[NSDictionary class]])
{
NSDictionary *objDict = (NSDictionary *)object;
ECGraphItem *tempItemi = [[ECGraphItem alloc]init];
NSString *str = [objDict objectForKey:#"title"];
NSLog(#"str value%#",str);
float f=[str floatValue];
tempItemi.isPercentage=YES;
tempItemi.yValue=f;
tempItemi.width=30;
NSArray *items = [[NSArray alloc] initWithObjects:tempItemi,nil];
//in array need to pass all the initialized values
[graph drawHistogramWithItems:items lineWidth:2 color:[UIColor blackColor]];
}
}
Why dont you just make the array mutable and then add the object each time like this:
NSMutableArray *items = [[NSMutableArray alloc] init];
// a mutable array means you can add objects to it!
for (int i = 0; i< [Array count]; i++)
{
id object = [Array objectAtIndex:i];
if ([object isKindOfClass:[NSDictionary class]])
{
NSDictionary *objDict = (NSDictionary *)object;
ECGraphItem *tempItemi = [[ECGraphItem alloc]init];
NSString *str = [objDict objectForKey:#"title"];
NSLog(#"str value%#",str);
float f=[str floatValue];
tempItemi.isPercentage=YES;
tempItemi.yValue=f;
tempItemi.width=30;
[items addObject: tempItemi];
//in array need to pass all the initialized values
}
}
[graph drawHistogramWithItems:items lineWidth:2 color:[UIColor blackColor]];
Anyways items in your original code will be reinitializing each time and you are drawing a new histogram each time so your code won't work... This should work...
The code you have written is ok but,
NSArray *items will always contain only one item at each loop.
just declare that outside for loop as NSMutableArray,
and go with the same code you are using.
As you said you want to make variable dynamically as
ECGraphItem *tempItemi = [[ECGraphItem alloc]init];
here i will be changing in the loop,
You can create a NSDictionary with key/value as per with your tempItem1/2/3/4.... as key and save values by alloc/init.
Then instead of a variable tempItem32, you will be using [dict valueForKey:#"tempItem32"].
EDIT:
Check this example if this may come handy
NSMutableDictionary *dict=[NSMutableDictionary new];
for (int i=1; i<11; i++) {
NSString *string=[NSString stringWithFormat:#"string%d",i];
[dict setObject:[NSString stringWithFormat:#"%d", i*i] forKey:string];
}
NSLog(#"dict is %#",dict);
NSString *fetch=#"string5";
NSLog(#"val:%#, for:%#",[dict valueForKey:fetch],fetch);

Display NSMutableArray in UIlabel in xcode

I have to display NSmutableArray data in UIlabel .But only the last index text is getting added .Here is my code
marray:
(
{
ID=1;
}
{
ID="2"
}
)
for(int i=0;i<[marray count];i++)
{
eventName=[[arr2 objectAtIndex:i]objectForKey:#"Code"];
label.text=[NSString stringWithFormat:#"ID :%#",eventName ];
}
I have to display these ID's in UIlabel with text as : 1 , 2
How can I do it?
you can append string to NSString object than use that object in label like bellow
NSMutableString *lblstr=#"ID :";
for (int i=0; i<[marray count]; i++) {
eventName=[[arr2 objectAtIndex:i]objectForKey:#"Code"];
[lblstr appendString:[NSString stringWithFormat:#"%#",eventName ]];
}
label.text=lblstr;
You are running a for loop which will continue executing till its last increment . So the last value in the array would be displayed. So what you can do is that you can add a timer instead of a for loop that is if you want to show your NSmutableArray as changing in the UILabel.
EDIT:
-(IBAction) rotate3
{
NSString *number = [self.dayArray description];
NSArray *array = [[NSArray alloc] initWithObjects: #"0", #"1", #"2", #"3", #"4", #"5" ,#"6", #"7", #"8",#"9",#"10",#"11",#"12",#"13", #"14", #"15", #"16", #"17", #"18", #"19",nil];
numberCount++;
timer=[NSTimer scheduledTimerWithTimeInterval:5.0 target:self selector:#selector(rotate3 )userInfo:nil repeats:YES];
self.dayArray = array;
[array release];
label.text = [NSString stringWithFormat:#"Day %# ", number];
}
Also check these links How to update UILabel programmatically in iOS and How to display an NSArray in a UILabel and use timer
Try the below Code.
NSString *temp=#"";
for(int i=0;i<[marray count];i++)
{
//eventName=[[arr2 objectAtIndex:i]objectForKey:#"Code"];
temp=[temp stringByAppendingString:[[arr2 objectAtIndex:i]objectForKey:#"Code"]];
temp=[temp stringByAppendingString:#" ,"];
}
temp = [temp substringToIndex:[temp length]-1];
label.text=[NSString stringWithFormat:#"ID :%#",temp ];
NSMutableString *str = [[NSMutableString alloc] init];
for(int i=0;i<[marray count];i++)
{
NSString *temp = [NSString stringWithFormat:#"%d - %#\n",i+1, [[arr2 objectAtIndex:i]objectForKey:#"Code"]];
[str appendString:[NSString stringWithFormat:#"%#",temp]];
//sleep(0.05); //Remove comment this line may help ! **Tricky Line**
}
label.text = str;
[str release];
You may create an array of objects (indexes) and use componentsJoinedByString:
NSString* str = [array componentsJoindeByString: #", "];
Or using your code, replacing
label.text=[NSString stringWithFormat:#"ID :%#",eventName ];
with:
label.text=[label.text stringByAppendingFormat:#", %#", eventName];

Load more pages in TTLauncherView

In my implementation of TTLauncherView, only loads the first page. Why?
I have 47 items in array, 47 items div 9 items by page, I should have 6 pages.
Thanks for helping.
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
NSMutableString *jsonString = [[NSMutableString alloc] initWithData:responseData encoding:NSUTF8StringEncoding];
NSDictionary *results = [jsonString JSONValue];
NSArray *photos = [[results objectForKey:#"photosets"] objectForKey:#"photoset"];
launcherView = [[TTLauncherView alloc] initWithFrame:self.view.bounds];
launcherView.backgroundColor = [UIColor whiteColor];
launcherView.delegate = self;
launcherView.columnCount = 3;
launcherView.persistenceMode = TTLauncherPersistenceModeNone;
NSMutableArray *itemArray = [[NSMutableArray alloc] init];
for (NSDictionary *photo in photos)
{
NSString *iconURLString = [NSString stringWithFormat:#"http://farm%#.static.flickr.com/%#/%#_%#_s.jpg",
[photo objectForKey:#"farm"], [photo objectForKey:#"server"], [photo objectForKey:#"primary"], [photo objectForKey:#"secret"]];
NSDictionary *title = [photo objectForKey:#"title"];
NSString *itemTitle = [title objectForKey:#"_content"];
TTLauncherItem *itemMenu = [[[TTLauncherItem alloc] initWithTitle:itemTitle
image:iconURLString
URL:nil
canDelete:NO] autorelease];
[itemArray addObject:itemMenu];
}
launcherView.pages = [NSArray arrayWithObject: itemArray];
[self.view addSubview:launcherView];
}
As I recall, TTLauncherView doesn't break up the TTLauncherItem's into pages automatically. You need an array of arrays. All of the launcher item's in the first array will be on the first page, all the launcher item's in the second array will be on the second page etc. It has been a long time since I've used it, but I think that's how it worked.
My modified code with the hint of #Darren
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
NSMutableString *jsonString = [[NSMutableString alloc] initWithData:responseData encoding:NSUTF8StringEncoding];
NSDictionary *results = [jsonString JSONValue];
NSArray *photos = [[results objectForKey:#"photosets"] objectForKey:#"photoset"];
NSMutableArray *itemArray = [[NSMutableArray alloc] init];
NSMutableArray *pageArray = [[NSMutableArray alloc] init];
NSNumber *countPage = [[NSNumber alloc] initWithInt:0];
for (NSDictionary *photo in photos)
{
NSString *iconURLString = [NSString stringWithFormat:#"http://farm%#.static.flickr.com/%#/%#_%#_s.jpg",
[photo objectForKey:#"farm"], [photo objectForKey:#"server"], [photo objectForKey:#"primary"], [photo objectForKey:#"secret"]];
NSString *photoCount = [photo objectForKey:#"photos"];
NSDictionary *title = [photo objectForKey:#"title"];
NSString *itemTitle = [title objectForKey:#"_content"];
TTLauncherItem *itemMenu = [[[TTLauncherItem alloc] initWithTitle:itemTitle
image:iconURLString
URL:nil
canDelete:NO] autorelease];
itemMenu.badgeValue = photoCount;
[itemArray addObject:itemMenu];
int value = [countPage intValue];
countPage = [NSNumber numberWithInt:value + 1];
if (countPage == [NSNumber numberWithInt:9]){
countPage = [NSNumber numberWithInt:0];
[pageArray addObject:itemArray];
itemArray = [[NSMutableArray alloc] init];
}
}
[pageArray addObject:itemArray];
launcherView = [[TTLauncherView alloc] initWithFrame:self.view.bounds];
launcherView.backgroundColor = [UIColor blackColor];
launcherView.delegate = self;
launcherView.columnCount = 3;
launcherView.persistenceMode = TTLauncherPersistenceModeNone;
launcherView.pages = pageArray;
[self.view addSubview:launcherView];
}

Autoreleased NSMutableArray not populated

I want to populate an array like this:
NSMutableArray *array = [self methodThatReturnsAnArray];
In the "methodThatReturnsAnArray"-method I create an array like this:
NSMutableArray *arrayInMethod = [[NSMutableArray alloc] init];
When I'm finished populating "arrayInMethod" I'm returning the array and in order to prevent a memory leak I'm using:
return [arrayInMethod autorelease];
However the "array"-variable is never populated. When removing the "autorelease" it works fine though. What should I do in order to make sure that the returned object i released?
EDIT
+ (NSMutableArray *)buildInstants:(NSArray *)huntsArray {
NSMutableArray *goGetObjects = [[[NSMutableArray alloc] init] autorelease];
for (int i = 0; i < [huntsArray count]; i++) {
NSDictionary *huntDict = [huntsArray objectAtIndex:i];
PHGoGet *goGet = [[PHGoGet alloc] init];
goGet.title = [huntDict objectForKey:#"title"];
goGet.description = [huntDict objectForKey:#"description"];
goGet.start = [huntDict objectForKey:#"start"];
goGet.end = [huntDict objectForKey:#"end"];
goGet.ident = [huntDict objectForKey:#"id"];
if ((CFNullRef)[huntDict objectForKey:#"image_url"] != kCFNull) {
goGet.imageURL = [huntDict objectForKey:#"image_url"];
} else {
goGet.imageURL = nil;
}
if ((CFNullRef)[huntDict objectForKey:#"icon_url"] != kCFNull) {
goGet.iconURL = [huntDict objectForKey:#"icon_url"];
} else {
goGet.iconURL = nil;
}
goGet.longitude = [huntDict objectForKey:#"lng"];
goGet.latitude = [huntDict objectForKey:#"lat"];
goGet.companyIdent = [huntDict objectForKey:#"company_id"];
[goGetObjects insertObject:goGet atIndex:i];
[goGet release];
}
return [[goGetObjects copy] autorelease];
}
Try using the convienence method for NSMutableArray... change:
NSMutableArray *arrayInMethod = [[NSMutableArray alloc] init];
To...
NSMutableArray *arrayInMethod = [NSMutableArray array];
array will return an autoreleased object.
First of all, I recommend you not to return a NSMutableArray from any method. It's better to use NSArray for that to avoid some very difficult to debug problems. My proposition is:
You declare the mutable array and populate it:
NSMutableArray *arrayInMethod = [[[NSMutableArray alloc] init] autorelease];
Then you return an autoreleased copy:
return [[arrayInMethod copy] autorelease];
And finally, when you take the returned array, you make it mutable again (only if you need to change it):
NSMutableArray *array = [[self methodThatReturnsAnArray] mutableCopy];
When you're done with the array, you release it:
[array release];

Objective-C - Concatenating strings separated by pipes

I would like to loop through an array strings and add them to an NSString in the following way:
NSMutableArray *emailsArray = [[NSMutableArray alloc] initWithObjects:#"One", #"Two", #"Three", nil];
for (id email in emailsArray {
NSString *emails = ??;
}
So the final NSString should be the following:
NSString *emails = #"One|Two|Three";
Use [emailsArray componentsJoinedByString:#"|"] for this.
Sample:
NSMutableArray *emailsArray = [[NSMutableArray alloc] initWithObjects:#"One", #"Two", #"Three", nil];
NSString *emails = [emailsArray componentsJoinedByString:#"|"];
Here you'll have emails = #"One|Two|Three".