dynamically created labels are overridden - iphone

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.

Related

How to set font to ALL of my text field?

I have this code and it's working :
[_fieldEmail setFont:[UIFont fontWithName:#"ABeeZee-Regular" size:14]];
[_fieldPassword setFont:[UIFont fontWithName:#"ABeeZee-Regular" size:14]];
[_fieldRegisterName setFont:[UIFont fontWithName:#"ABeeZee-Regular" size:14]];
[_fieldRegisterEmail setFont:[UIFont fontWithName:#"ABeeZee-Regular" size:14]];
[_fieldRegisterPassword setFont:[UIFont fontWithName:#"ABeeZee-Regular" size:14]];
[_titleLogin setFont:[UIFont fontWithName:#"Raleway-ExtraLight" size:28]];
[_titleRegister setFont:[UIFont fontWithName:#"Raleway-ExtraLight" size:28]];
[_titleVote setFont:[UIFont fontWithName:#"Raleway-ExtraLight" size:28]];
also I have this code to apply padding left and padding right for each text field that I have :
UIView *fieldEmail = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 10, 10)];
_fieldEmail.leftViewMode = UITextFieldViewModeAlways;
_fieldEmail.leftView = fieldEmail;
UIView *fieldPassword = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 10, 10)];
_fieldPassword.leftViewMode = UITextFieldViewModeAlways;
_fieldPassword.leftView = fieldPassword;
UIView *fieldRegisterName = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 10, 10)];
_fieldRegisterName.leftViewMode = UITextFieldViewModeAlways;
_fieldRegisterName.leftView = fieldRegisterName;
UIView *fieldRegisterEmail = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 10, 10)];
_fieldRegisterEmail.leftViewMode = UITextFieldViewModeAlways;
_fieldRegisterEmail.leftView = fieldRegisterEmail;
UIView *fieldRegisterPassword = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 10, 10)];
_fieldRegisterPassword.leftViewMode = UITextFieldViewModeAlways;
_fieldRegisterPassword.leftView = fieldRegisterPassword;
but I think it's an ugly code. because I have to set every text field and label one by one. Is it any better way to simplify this?
thank you very much..
I wouldn't do this way. If you check your code, you have a lot of similar pattern for your TextField.
Why don't create customTextField which is inherited from UITextField? And then, what you need is set font, leftViewMode and leftView in your customTextField class. When use it, just alloc with frame. Done!
In iOS 5 and later you can use the UIAppearance API to give a consistent style to your controls. Which iOS framework are you targeting?
OR
As suggested by Brain you can create a custom TextField and use that instead of UITextField. Your custom TextField would of course inherit from the UITextField but it will change different properties which you desire.
Make two arrays:
NSArray* fields= #[ _fieldEmail, _fieldPassword, _fieldRegisterName, _fieldRegisterEmail, _fieldRegisterPassword ];
NSArray* titles = #[ _titleLogin, _titleRegister, _titleVote ];
Then use makeObjectsPerformSelector:withObject: to execute a method call on all the array objects:
UIFont* font1= [UIFont fontWithName: #"ABeeZee-Regular" size: 14];
UIFont* font2= [UIFont fontWithName:#"Raleway-ExtraLight" size:28];
[fields makeObjectsPerformSelector: #selector(setFont:) withObject: font1];
[titles makeObjectsPerformSelector: #selector(setFont:) withObject: font2];
As for the second task you can simply use iteration and put the created UIView objects in a mutable array, if you need to use them later. If you want call them by name, then also a dictionary is a good idea:
NSArray* keys= #[ #"fieldEmail", #"fieldPassword", #"fieldRegisterName", #"fieldRegisterEmail", "fieldRegisterPassword" ];
NSMutableDictionary* fieldsDict= [[NSMutableDictionary alloc] init];
for(NSString* key in keys) {
UIView* field= [[UIView alloc] initWithFrame:CGRectMake(0, 0, 10, 10)];
field.leftViewMode= UITextFieldViewModeAlways;
field.leftView= field; // I hope that this property is weak
[fieldsDict setObject: field forKey: key];
}
You could try to loop through all the subviews and check if they are an instance of UITextField or any subclass of UITextField. If they are, you can set the font property.
I quickly wrote some sample code to show you how you could do this:
for (UIView *subview in [[self view] subviews]) {
if ([subview isKindOfClass:[UITextField class]]) {
UITextField *textField = (UITextField *)subview;
[textField setFont:[UIFont fontWithName:#"ABeeZee-Regular" size:14.f]];
}
}
Be aware of the fact that this code only loops through the 'closest' children of [self view] and thus won't modify views deeper in the hierarchy.

How to remove the nsmutablearray's object from subview?

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.

iOS - UIScrollView doesn't update its content and some UIViews disappear after reload

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

Label refuses to disappear with [label setHidden:YES]; command in a if-method?

I am trying to customize my tableView in my IOS app. When my tableView(or rather array) is empty, I want to display a customized label instead of the items in the tableView. The label I am referring to is "label0". But something is terribly wrong, my [label0 setHidden:YES]; or [label0 setHidden:NO]; only works in the first block of the if "method"? In the second block (if else) nothing happens no matter what I try to set the label as (hidden or shown).
What have I missed? I cannot see my own fault?
- (UIView *) tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
{
UIView *headerView = [[[UIView alloc] initWithFrame:CGRectMake(0, 0, tableView.bounds.size.width, 30)] autorelease];
UILabel *label0 = [[[UILabel alloc] initWithFrame:CGRectMake(0, 25, tableView.bounds.size.width - 0, 100)] autorelease];
if ([self.searchResults count] == 0){
headerView.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:#"lista2.png"]];
UILabel *label = [[[UILabel alloc] initWithFrame:CGRectMake(5, 3, tableView.bounds.size.width - 5, 18)] autorelease];
label.text = #"Information";
label.textColor = [UIColor whiteColor];
label.backgroundColor = [UIColor clearColor];
[headerView addSubview:label];
label0.text = #"Test test test";
label0.textColor = [UIColor blackColor];
label0.backgroundColor = [UIColor whiteColor];
[tableView addSubview:label0];
[label0 setHidden:NO];
}
else {
headerView.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:#"lista2.png"]];
UILabel *label2 = [[[UILabel alloc] initWithFrame:CGRectMake(5, 3, tableView.bounds.size.width - 5, 18)] autorelease];
label2.text = #"Search results";
label2.textColor = [UIColor whiteColor];
label2.backgroundColor = [UIColor clearColor];
[headerView addSubview:label2];
[label0 setHidden:YES];
}
return headerView;
}
EDIT
I have moved the code to viewDidLoad and set the property for the UILabel. This have unfortunately not solved my problem....
UILabel *label0 = [[[UILabel alloc] initWithFrame:CGRectMake(0, 25, tableView.bounds.size.width - 0, 100)] autorelease];
[tableView addSubview:label0];
if ([self.searchResults count] == 0){
label0.text = #"Test test test";
label0.textColor = [UIColor blackColor];
label0.backgroundColor = [UIColor whiteColor];
[label0 setHidden:NO];
}
else {
[label0 setHidden:YES];
}
This is because your label0 is created every time this method is called so in "else" you are referring to totally different object (not the one that you added to tableView when array was empty).
You shouldn't be adding subviews to tableView from this method. Consider using viewDidLoad. That way you will be adding label0 only once. To achieve that add label0 as property of your viewController.
You forgot to add label0 as subview please put this line in the else statement
[tableView addSubview:label0];
also I cannot see any benefit from doing so. I believe you can just hide the table view and show another view that has the label. but nesting views that way is not good when you come back to debug this code after 1 month you will struggle to understand it.
You say in your edit that you set the property for the UILabel (I assume you mean that you have a property called label0?). If this is so, then when you alloc init your label, it should be self.label0 = ..... not UILabel *label0 = .....

Potential Memory leak, and I don't know why

I have the following code which adds a label into a footer of a UITableView, so that I can format the text (white, etc.)
It works ok, but it gives me a leak warning for the "headerLabel" when analyzing it on the line with the "return"
// create the parent view that will hold header Label
UIView* customView = [[UIView alloc] initWithFrame:CGRectMake(0.0, 15.0, 300.0, 44.0)];
// create the button object
UILabel * headerLabel = [[UILabel alloc] initWithFrame:CGRectZero];
headerLabel.backgroundColor = [UIColor clearColor];
headerLabel.opaque = NO;
headerLabel.textColor = [UIColor whiteColor];
headerLabel.highlightedTextColor = [UIColor whiteColor];
headerLabel.font = [UIFont systemFontOfSize:14];
headerLabel.textAlignment=UITextAlignmentCenter;
headerLabel.frame = CGRectMake(10.0, 0.0, 300.0, 75.0);
headerLabel.numberOfLines=4;
if (section==0) {
headerLabel.text = #"If turned off, the last used settings will be used on the next session\n\n"; // i.e. array element
}
[customView addSubview:headerLabel];
//[headerLabel release];
return customView;
// [customView release];
I've tried to put the release here and there, but it's always the same.
I'd appreciate some feedback from you guys.
try
[headerLabel release];
return [customView autorelease];
You have to release headerLabel before exiting the method:
[headerView release];
You probably should autorelease customView unless your method name includes the words new, alloc or copy (in that case, the caller would have to release the returned view):
return [customView autorelease];
autorelease your customView and make sure you are releasing headerLabel after you add it as a subview. Anytime you call alloc/init you are taking ownership, you need to make sure you release those objects. Since you are returning customView from this method it makes sense to defer your release of that object (using autorelease) so it can be used by the calling object.
// create the parent view that will hold header Label
UIView* customView = [[[UIView alloc]
initWithFrame:CGRectMake(0.0, 15.0, 300.0, 44.0)]
autorelease];
// create the button object
UILabel * headerLabel = [[UILabel alloc] initWithFrame:CGRectZero];
headerLabel.backgroundColor = [UIColor clearColor];
headerLabel.opaque = NO;
headerLabel.textColor = [UIColor whiteColor];
headerLabel.highlightedTextColor = [UIColor whiteColor];
headerLabel.font = [UIFont systemFontOfSize:14];
headerLabel.textAlignment=UITextAlignmentCenter;
headerLabel.frame = CGRectMake(10.0, 0.0, 300.0, 75.0);
headerLabel.numberOfLines=4;
if (section==0) {
headerLabel.text = #"If turned off, the last used settings will be used on the next session\n\n"; // i.e. array element
}
[customView addSubview:headerLabel];
[headerLabel release];
return customView;
Based on the code sample you've got here, the first release would be correct. (Releasing after the return statement wouldn't make sense). You took ownership of the object when you created it, and you need to release it.
You can use Instruments to track where object is being retained and released; you can see a history of the leaky object to see exactly what's going on. That would be your best bet here.  
Launch your app with the Leaks instrument, and when you find the leaking object, click the arrow to the right of the address. This will show you the object's history - every retain and release.