i have nsmutablearray in which i saved some character means alphabets now what i want is
to display these objects as subview on screen. and i did it easily..and em doing this through loop.. i am accessing arrays object one by one by which i can add these as subview but now em unable to remove these from super view.
I want to remove these labels. how can i do that?
UILabel *myLabel;
UIImageView *image;
for (int j = 0; j<[intValues count];j++) {
image = [allGridImages objectAtIndex:j];
image.userInteractionEnabled=NO;
image.multipleTouchEnabled=NO;
image.image= [UIImage imageNamed:#"box-1.png"];
title = [allGridBoxesTitle objectAtIndex:j];
myLabel = [[UILabel alloc] initWithFrame:CGRectMake(15, 1, 45, 45)];
myLabel.text = [allGridBoxesTitle objectAtIndex:j];
myLabel.textColor = [UIColor grayColor];
myLabel.font = [UIFont boldSystemFontOfSize:26.0f];
myLabel.backgroundColor = [UIColor clearColor];
[image addSubview:myLabel];
Try this method
- (void)removeAllLabels
{
for (UIView *view in self.view.subviews)
{
if ([view isKindOfClass:[UILabel class]])
{
[view removeFromSuperview];
}
}
}
You could do this before adding the new label:
[image.subviews makeObjectsPerformSelector:#selector(removeFromSuperview)];
This will instruct any subviews to remove themselves.
However, this depends on the fact that a UIImageView doesn't have any subviews in the current version of iOS, which may not always be true. It'd be better to actually keep track of these labels and specifically remove them when you're finished with them, or even reuse them instead of making new ones every time.
Related
I have UITableViewController with UIScrollView inside UIView as its header.
UIScrollView is used to display slideshow of images:
UITableView
-UITableViewHeaderView
-UIView
-UIScrollView
-UIImageView
...
-UIPageControl
Every image has a subview with its title and description:
UIImageView
-UIView
-UILabel
-UILabel
When I need to update my tableView a delegate method is called which reloads data in a tableView and calls addImages method:
- (void)eventsUpdated
{
if ([self respondsToSelector:#selector(setRefreshControl:)])
[self.refreshControl endRefreshing];
[self.tableView reloadData];
[self addImages];
}
Here is how I add my images:
- (void)addImages
[self.scrollView.subviews makeObjectsPerformSelector:#selector(removeFromSuperview)];
for (int i = 0; i < images.count; i++) {
CGRect frame;
frame.origin.x = self.scrollView.frame.size.width * i;
frame.origin.y = 0;
frame.size = self.scrollView.frame.size;
UIImageView *subview = [self createImageViewForEvent:[images objectAtIndex:i] inFrame:frame];
subview.frame = frame;
[self.scrollView addSubview:subview];
}
self.scrollView.contentSize = CGSizeMake(scrollView.frame.size.width*images.count, scrollView.frame.size.height);
pageControll.currentPage = 0;
pageControll.numberOfPages = images.count;
}
- (UIImageView *)createImageViewForEvent:(Event *)event inFrame:(CGRect)frame
{
UIImage *image;
NSString *imageName = [event.imageName lastPathComponent];
NSString *bundleFilePath = [[NSBundle mainBundle] pathForResource:[imageName stringByDeletingPathExtension] ofType:[imageName pathExtension]];
image = [UIImage imageWithContentsOfFile:bundleFilePath];
UIImageView *output = [[UIImageView alloc] initWithImage:image];
output.frame = frame;
UIView *descriptionView = [[UIView alloc] initWithFrame:CGRectMake(0, frame.size.height*0.7, frame.size.width, frame.size.height*0.3)];
descriptionView.backgroundColor = [UIColor colorWithRed:0 green:0 blue:0 alpha:0.5];
descriptionView.alpha = 1.0;
UILabel *header = [[UILabel alloc] initWithFrame:CGRectMake(10, 5, frame.size.width-20, 12)];
header.textColor = [UIColor colorWithRed:210/256.0 green:217/256.0 blue:231/256.0 alpha:1.0];
header.font = [UIFont fontWithName:#"Helvetica" size:17];
header.backgroundColor = [UIColor clearColor];
header.lineBreakMode = UILineBreakModeTailTruncation;
header.numberOfLines = 1;
UILabel *description = [[UILabel alloc] initWithFrame:CGRectMake(10, 22, frame.size.width-20, 28)];
description.textColor = [UIColor colorWithRed:255/256.0 green:255/256.0 blue:255/256.0 alpha:1.0];
description.font = [UIFont fontWithName:#"Helvetica" size:12];
description.backgroundColor = [UIColor clearColor];
description.lineBreakMode = UILineBreakModeTailTruncation;
description.numberOfLines = 2;
header.text = event.title;
[descriptionView addSubview:header];
description.text = event.shortDesription;
[descriptionView addSubview:description];
[output addSubview:descriptionView];
return output;
}
After first launch everything works fine, but if I try to reload my tableView and call addImages again, all UILabels disappear, only UIImageView and UIView are visible.
UPD:
What I have noticed, is that my UILabels appear after some time, approximately after 30 seconds. I have never experienced something similar before
UPD 2:
After I reload my tableView and scrollview, scrollView's content is not updated right away, only after I start scrolling
I reproduced a sample project from the code you posted, and didn't find any refreshing issues on the labels nor on any other component. This leads me to think the problem is not in the code you posted, but rather somewhere else.
Usually when you see such a delay, it is because some code that should not be running in parallel, is running in parallel.
I would suggest you check how and when you perform your call to eventsUpdated. You must make sure that call is performed on the main thread, and only once your array of events has finished updating. To check that, you can add add the following line in eventsUpdated:
NSLog(#"Current: %#, main: %#", [NSThread currentThread], [NSThread mainThread]);
Please post the log! :-)
I would suggest you also add to your question the code from the method that calls eventsUpdated, as it could also be of help.
At first, never do something like
[scrollView.subviews makeObjectsPerformSelector:#selector(removeFromSuperview)];
Scroll view has some internal views (scroll indicators, for example), so you're removing them which may dealloc them and cause strange crashes any time later.
As for your problem - try calling bringSubviewToFront: of your UIImageView to get your labels infront of everything else
i am working on one application in which i have added 5 labels dynamically in a function.when i recall the same function the labels are overridden on the previously created labels in spite of releasing the labels on each creation.
for(int i = 1; i < [array count]; i++)
{
CGRect lblframe = CGRectMake(count, ycord, width, height);
UILabel *label = [[UILabel alloc] initWithFrame:lblframe];
label.backgroundColor = [UIColor blackColor];
label.font = [UIFont systemFontOfSize:17];
label.textAlignment = UITextAlignmentCenter;
label.textColor = [UIColor colorWithRed:(188/255.f) green:(149/255.f) blue:(88/255.f) alpha:1.0];;
label.text = [arr objectAtIndex:i];
count = count + xcord;
[subcatScroll addSubview:label];
[label release];
}
Write below code before for loop to get your requirement:
for (id object in [subcatScroll subviews]) {
[object removeFromSuperview];
}
I'm not sure I completely follow, so correct me if I'm misunderstanding.
Every time you call this function, you are adding a number of new labels. So if you call this function the second time, assuming 'count', 'ycord', 'width', and 'height' correspond with the values that the first call had, you are obviously adding a second group of labels in the same place as the first ones which are now directly on top of one another. You are not "overriding" the old labels, you are placing a second group directly ontop of the old ones.
Calling "release" on each label, only means you are decreasing the retainCount by 1. This number is used for memory management only. This means if you now remove the labels from the view the memory is released.
CGRect lblframe = CGRectMake(10.0, ycord, 200.0, 20.0);
UILabel *label = [[UILabel alloc] initWithFrame:lblframe];
NSLog(#"retainCount of label: %d", [label reatinCount]); // will print "1" since you called alloc
[self.view addSubview:label];
NSLog(#"retainCount of label: %d", [label reatinCount]); // will print "2" since adding to subview increases retaincount by one
[label release];
NSLog(#"retainCount of label: %d", [label reatinCount]); // will print "1" since you released
[label removeFromSuperview]; // will decrease retainCount of label to "0" and therefore free the memory
so say you wanted to remove the previously created labels from the view, you would have to do so. Either keep a reference to each of them and call "removeFromSuperview" on each of them.
If the only thing in the view where you're adding the labels, you can also just remove every subview that was added to it like so:
// remove old labels
for (UILabel *aLabel in [self.view subviews]) [aLabel removeFromSuperview];
NSArray *myArray = [NSArray arrayWithObjects:#"I", #"II", #"III", #"IV", nil];
for (int i=0; i<[myArray count]; i++) {
float ycord = i*40.0;
CGRect lblframe = CGRectMake(10.0, ycord, 200.0, 20.0);
UILabel *label = [[UILabel alloc] initWithFrame:lblframe];
label.backgroundColor = [UIColor blackColor];
label.font = [UIFont systemFontOfSize:17];
label.textAlignment = UITextAlignmentCenter;
label.textColor = [UIColor colorWithRed:(188/255.f) green:(149/255.f) blue:(88/255.f) alpha:1.0];;
label.text = [myArray objectAtIndex:i];
[self.view addSubview:label];
[label release];
}
I hope this helped, but providing further info on what you're trying to do may make it easier to help you.
cellForRowAtIndexPath:
CGRect nameValueRect = CGRectMake(80, 5, 200, 15);
UILabel *nameValue = [[UILabel alloc] initWithFrame:
nameValueRect];
nameValue.tag = kNameValueTag;
[cell.contentView addSubview:nameValue];
[nameValue release];
...
NSUInteger row = [indexPath row];
NSDictionary *rowData = [self.computers objectAtIndex:row];
UILabel *name = (UILabel *)[cell.contentView viewWithTag:
kNameValueTag];
name.text = [rowData objectForKey:#"Name"];
This code is from a tutorial that I'm using which creates a subview within the cell to add some text.
However, what I want to do is instead of adding text I will place an image.
I tried UIImageView *posterValue = [[UIImageView alloc] initWith... oh there's no initWithFrame for UIImageView.
Perhaps, someone can explain the process for an image. Do I even need to set the frame size for a UIImageView? I would need to position it.
EDIT:
my new code:
UIImageView *posterValue = [[UIImageView alloc] initWithFrame:CGRectMake(0,0,105,175)];
posterValue.tag = kPosterValueTag;
[cell.contentView addSubView:posterValue];
[posterValue release];
addSubView is not working for UIImageView. Says UIView may not respond to addSubView
It's addSubview not addSubView - case matters.
example if there is a method addLabel:
- (void)addLabel {
for (NSInteger i = 0; i < 5; i ++) {
UILabel *label = [[UILabel alloc] init];
[label setText:#"label"];
[[self view] addSubView:label];
[label release];
}
}
and the method is called whenever a button is fired.
Does it need to remove all the label from the subviews first (removeFromSuperView:) before addSubview again?
First, you have to give some coordinate to UILabel. So that, it can display at proper place.
You can use following line for that:
UILabel *lblTaskTitle = [[UILabel alloc] initWithFrame:CGRectMake(45.0, 5, 200.0, 35.0)];
Another thing is that, it will be better if you remove other label. (It's not necessary, but it's good practice).
You can do it in following way:
UILabel *lbl = nil;
NSArray *Arraylbl = [self.view subviews];
for (lbl in Arraylbl){
if ([lbl isKindOfClass:[UILabel class]]){
[lbl removeFromSuperview];
}
}
Hope it will be fine for you.
Let me know in case of any difficulty.
Yes you have to remove all the previous labels from super view otherwise they all will be added above the previous existing labels, so the new labels would not be understandable.
I have an app where I create many uiviews and add them to the self.view of the UIViewController. My app is running really slowly. I am releasing all of my objects and have no memory leaks (I ran the performance tool). Can anyone tell me what could be making my app so slow? (code is below)
[EDIT] The array has around 30 items. [/EndEdit]
Thanks so much!
Here is the code for the loadView method of my UIViewController:
- (void)loadView {
UIView *contentView = [[UIView alloc] initWithFrame:[[UIScreen mainScreen] applicationFrame]];
contentView.backgroundColor = [UIColor whiteColor];
self.view = contentView;
[contentView release];
int length = 0;
for(NSString *item in arrayTips)
{
length++;
[item release];
}
int index = 0;
for(NSString *item in arrayTitles)
{
SingleFlipView *backView = [[SingleFlipView alloc] initWithFrame:[[UIScreen mainScreen] applicationFrame]];
backView.userInteractionEnabled = YES;
backView.backgroundColor = [UIColor whiteColor];
[backView setViewIndex:index];
[backView setLastViewIndex:length];
CGRect labelFrame = CGRectMake(10.0f, 0.0f, 300.0f, 30.0f);
UILabel *backLabel = [[UILabel alloc] initWithFrame:labelFrame];
backLabel.textAlignment = UITextAlignmentCenter;
backLabel.userInteractionEnabled = YES;
backLabel.text = item;
backLabel.font = [UIFont fontWithName:#"Georgia" size:24.0f];
backLabel.textColor = [UIColor blackColor];
backLabel.backgroundColor = [UIColor whiteColor];
CGRect textFrame = CGRectMake(10.0f, 30.0f, 300.0f, 110.0f);
UITextView *tbxView = [[UITextView alloc] initWithFrame:textFrame];
tbxView.textAlignment = UITextAlignmentCenter;
tbxView.userInteractionEnabled = YES;
tbxView.editable = FALSE;
tbxView.text = [arrayTips objectAtIndex:index];
tbxView.font = [UIFont fontWithName:#"Arial" size:14.0f];
tbxView.textColor = [UIColor blackColor];
tbxView.backgroundColor = [UIColor whiteColor];
//CGRect labelFrame = CGRectMake(10.0f, 0.0f, 84.0f, 30.0f);
UIImage *nextTip = [[UIImage imageNamed:#"NextTip.png"] retain];
UIImageView *nextTipView = [ [ UIImageView alloc ] initWithImage:nextTip];
nextTipView.frame = CGRectMake(230.0f, -10.0f, 84.0f, 30.0f);
nextTipView.userInteractionEnabled = YES;
UIImageView *view = [[ UIImageView alloc ] init];
view.userInteractionEnabled = YES;
if(self.sexString == #"Men")
{
UIImage *imgTip = [[UIImage imageNamed:#"feet_small.jpg"] retain];
view.image = imgTip;
view.frame = CGRectMake(0.0f, 110.0f, 416.0f, 228.0f); //59*161
[imgTip release];
}
[backView addSubview:view];
[backView addSubview:tbxView];
[backView addSubview:backLabel];
//[backView addSubview:nextTipView];
[self.view addSubview:backView];
[backView release];
[backLabel release];
[nextTip release];
[nextTipView release];
[tbxView release];
[view release];
index++;
[item release];
}
}
It's going to depend upon how many items are in arrayTitles. If you're just adding one or two of these, you shouldn't see a HUGE slowdown; more, and you will. You should probably take a look at the way UITableView handles its cells; only create these as they're actually needed/used, or, better yet, only create one of these, and set its contents on-the-fly.
A few other notes:
== is not a valid string comparison operator in Objective-C; use [string1 isEqualTo: string2]
It appears you're trying to place a lot of these on screen at the same time, which doesn't seem like it would make a lot of sense.
it looks like you've got a spurious [item release] at the end there (you're never retaining item, so there's no need to release it.
the whole first loop ( for(NSString *item in arrayTips)... frightens and confuses me; items in NSArrays are already retained by the array. You shouldn't have to explicitly retain/release them in this way.
Having deep view hierarchies can lead to slow downs that you can often fix through flattening them some with custom views, but if you are using simple views you can have dozens on the screen with no perceptible performance impact, so in general I recommend ignoring how many views you have when you are developing, and then reducing the view count if it proves to be a performance problem.
Having said that, you appear to be setting up something with an unboundedily large number of views which is not good. Without knowing how many entries there are in array titles I can't tell you what is going on exactly, but I suspect that while the actual visual heiarchy with each backView you are creating is fine, making a backView for each item in the array and using indices to have the front most one hide all the other ones behind it is causing you to have way too many views.
So, how to test it:
Add a break to the bottom of your for loop. Make the loop drop out after a single iteration and see if performance improves. If it does, then the huge view hierarchies are your issue. YOu may have to hack up the routine that changes the indexes to make sure it never swaps to an invalid index to test.
If that is the case you have a few options. You could implement a custom view and flatten every backview into a single view, but depending on how many you have that mat not be sufficient, and it is more work than simply building the back views the way you currently are, but on demand instead of at load time:
1) Refactor the code in your for loop into a separate method that makes a backView for a specific title and attaches it to the view at that time.
2) Where ever you are currently altering the indexes to make the backview visible, instead call the new method to actually build and attach the backview at that time
Don't forget to make as many of your views opaque as you can. Transparent views are a major source of performance issues.