If this is a noob question, I apologize in advance. I just want to clarify how the relationship between the objects inside an array relates to the actual object. For example:
UILabel *labelOne = //init stuff
[self.view addSubview: labelOne];
[labelArray addObject: labelOne];
Now if I change the property of the object inside the array like so:
[[labelArray objectAtIndex:0] setText:#"NEW STRING"];
Am I updating just what is inside the array or will it also update my initial UILabel and therefore reflect the change on the view? Are there any situations where the results might differ? (i.e. releasing initial UILabel with object still in the array, etc.)
The array stores a strong reference to the object, but doesn't copy it. So there is only ever one label. So the code you showed will update the label's text.
It will change the UILabel you have on screen since NSArray only holds references to objects, it doesn't make copies. So whatever labels you are putting into the array are just references to what you've already created.
Yes it will update your initial UILabel and therefore reflect the change on the UIView as reference of UILabel is stored in array.
IT will update your initial UILabel as NSArray is holding the reference of original UILabel and not there copies
Your labelArray will contain pointers to each adding object. And it increment retain counter for each adding object. So [[labelArray objectAtIndex:0] setText:#"NEW STRING"]; will change labelOne.text too, because you reference to one UILabel object.
UILabel *labelOne = //init stuff
[self.view addSubview: labelOne];
[labelArray addObject: labelOne];
[[labelArray objectAtIndex:0] setText:#"NEW STRING"];
The label which you add to labelArray is the same object as initial labelOne.
But if you what to avoid such behavior you can add a copy of labelOne to labelArray by using copy method.
[labelArray addObject: [labelOne copy]];
This will give you a copy of labelOne object in you labelArray. And this copy will not be changed after you change label text.
So after you get labelOne from array the label will be in initial state.
Yes this will change the value of the label text displayed on the view. See here I have simulate the scenario..
Code....
UILabel *labelOne = [[UILabel alloc] initWithFrame:CGRectMake(20, 30, 200, 20)];
labelOne.text = #"Dilip";
[self.view addSubview: labelOne];
NSMutableArray *labelArray =[[NSMutableArray alloc] init];
[labelArray addObject: labelOne];
[[labelArray objectAtIndex:0] setText:#"Hi Dilip"];
And here is the output..
You can see that instead of text "Dilip" there is displayed text is "Hi Dilip".
The labelArray stores only the reference of the labelOne. so if you change anything in the labelArray affect the labelOne.
Related
I have an UILabel pinter in my UIView (using ARC).
I dynamically create a lot of text and override the the same pointer every time.
I thought, that if I use the same pointer all the time, and override it with the new objects, they still be in my View, but the pointer of them will be deallocated. But as I see, my memory increase all the time, if the text was changed and the drawRect executed. Maybe someone know the better way to do that, or to fix this memory issue.
UPDATE: Code
#interface Bars : UIView{
NSMutableDictionary *dictCopy;
UILabel *pivotLabel;
}
for (a lot of times) {
pivotLabel = [[UILabel alloc] initWithFrame:frame];
pivotLabel.text = pivotText;
pivotLabel.backgroundColor = [UIColor clearColor];
pivotLabel.textColor = self.color;
[self addSubview:pivotLabel];
}
When you add a new label as a subview the parent view retains it. Nilling a pointer is not enough to remove it. To remove a label, do this:
[self.myLabel removeFromSuperview];
self.myLabel = nil;
A UITextView is created each time i click on ADD button. Y-axis value is altered(say, y+=100) every time i click ADD and so a set of UITextViews are created one below the other. I cant figure out how to differentiate and access a particular UITextView. Thanks for any help!
EDIT:
-(IBAction)access:(id)sender
{
int tg=[sender superview].tag;
UIView *view=(UIView *)[textView viewWithTag:tg-1];
}
tg-1 because im trying to access the previous UITextView and when i do this it returns NULL.
Store them on a NSMutableArray:
NSMutableArray * views = [[NSMutableArray alloc] init]
Your IBAction
-(IBAction)access:(id)sender{
int tg=[sender superview].tag;
UIView *view=(UIView *)[textView viewWithTag:tg-1];
[views addObject: views];
}
Then you can get all the references with a integer index with:
UIView * storedView = [views objectAtIndex: 1];
Use a view tag to differentiate the views and access them.
You don't say how you're creating the new views, but something like this should work:
UIView* new_view = [UITextView initWithFrame(...)];
new_view.tag = generate_tag()
Where the generate_tag() function generates whatever naming scheme makes sense for your application.
Here's my code:
if([pantallas objectForKey:par]){
UIView *vista= [[UIView alloc] initWithFrame:self.Botones.frame];
vista.backgroundColor= [UIColor brownColor];
CGSize la= CGSizeMake(50,60);
int cuantos= [part2 count];
NSArray *arr= [COLGenerales tileN:cuantos RectsOfSize:la intoSpaceOf:vista.frame withMaxPerRow:5 spaceVertical:10 spaceHorizontal:10];
for(int j=0; j<cuantos; j++){
UIButton *bot= [[UIButton alloc] initWithFrame:[[arr objectAtIndex:j] CGRectValue]];
bot.tag=j;
bot.titleLabel.text=par;
bot.titleLabel.hidden=true;
bot.imageView.image = [UIImage imageNamed:[[part2 allKeys] objectAtIndex:j]];
[bot addTarget:self action:#selector(registrar:) forControlEvents:UIControlEventTouchDown];
[vista addSubview:bot];
}
[pantallas setObject:vista forKey:par];
self.Botones= vista;
}else{
self.Botones= [pantallas objectForKey:par];
}
Botones is a simple view embedded into the view this class controls (first initiated by the Nib file), the class method of COLGenerales returns an array of CGRects coded as NSValues, and registrar: is a local method.
Everything gets properly set (I've thoroughly checked this with the debugger). The view gets successfully created, set, and added to the dictionary.
However, I absolutely never get the actual screen to change. I even included the background color change just to check if it isn't some kind of problem with the buttons. Nothing. Any suggested solution to this?
A property that is an IBOutlet does not have an intrinsic connection to the view hierarchy—it only makes it possible to populate that property from a xib. When you set self.Botones, you'll need to do something like the following:
[self.Botones removeFromSuperview];
self.Botones = newValue;
[self.BotonesSuperview addSubview:self.Botones];
If you update self.Botones in many places, and you always want the change reflected on-screen, you could add this into a setter implementation:
-(void)setBotones:(UIView*)newValue {
if (newValue != _Botones) {
[_Botones removeFromSuperview];
_Botones = newValue;
[self.BotonesSuperview addSubview:_Botones];
}
}
I recommend using a UINavigation controller that houses these two views.
You can reference this link Swapping between UIViews in one UIViewController
Basically, you create one view, removeSubview for the first and then add the second one with addSubview!
[view1 removeFromSuperview];
[self.view addSubview: view2];
Other reference sources:
An easy, clean way to switch/swap views?
How to animate View swap on simple View iPhone App?
Hopefully this helps!
For my iPad app, I am programmatically creating several UIImage views that I display on the screen. The code looks basically like this:
for(ModelObject *model in ModelsList){
//create a UIImage view from the model object
UIImageView *icon = [[UIImageView alloc] initWithFrame:model.icon_frame];
icon.image = [UIImage imageWithContentsOfFile:[[NSBundle mainBundle] pathForResource:model.icon_path ofType:#"png"]];
//add the imageview to a mutable array to keep track of them
[myImageViews addObject:icon];
// add the view as a subview
[self.view addSubview:icon];
}
So now I have a bunch of icons displayed on the screen. But I would like to intercept touch events from the UIImageViews that I created programmatically, so that it calls some other method, preferably with an argument containing the sender's id or some other distinguishing information that I can use to determine which UIImageView was touched.
What is the best practices way of accomplishing this?
I am new to iOS so recommended reading would also be greatly appreciated.
Please provide any applicable feedback, as I have no idea if this is common practice or even a decent way of doing things...
So basically what I did was keep a dictionary of ids that maps between the view object and the model objects, and then I look up the id of the sending view and find the appropriate model object, (I will then use that model object to load another view)
The code looks like this:
// in header
#property(nonatomic, retain) NSMutableDictionary *icons_to_models
// after creating a UIButton called icon
[icon setBackgroundImage:model.image forState:UIControlStateNormal];
[icon addTarget:self action:#selector(tappedIcon:) forControlEvents:UIControlEventTouchUpInside];
NSNumber *key = [NSNumber numberWithUnsignedInt:[icon hash]];
[icons_to_models setObject:model forKey:key];
...
//match sender to the icon that was pressed and
-(void)tappedIcon:(id)sender{
NSNumber *key = [NSNumber numberWithUnsignedInt:[sender hash]];
ModelObject *model = [icons_to_models objectForKey:key];
NSLog(#"tapped on: %#", model.name);
}
I am writing a fairly simple application which spawns a thread which ultimately calls the following method to put a UILabel at a certain location. I had expected ARC to clean up the labels as the method closed. I was wrong. :)
Is there a way to force these to be cleaned up or is there something obvious that I am missing? Thanks!
-(void) drawNumberLabel:(NSString *)labelText xloc:(float)xLocation yLoc:(float)yLocation {
UILabel *tempLabel;
tempLabel = [[UILabel alloc] initWithFrame:CGRectMake(xLocation, yLocation, 27.0, 59.0)];
tempLabel.font = [UIFont fontWithName:#"Helvetica" size:fontSize];
tempLabel.text = labelText;
tempLabel.backgroundColor = backgroundColor;
tempLabel.textColor = textColor;
[self addSubview:tempLabel];
}
What do you mean by "clean up the labels"? Are you expecting that tempLabel would be deallocated at the end of this method? It won't, because when you call [self addSubview:tempLabel], your view retains the label. When the superview is deallocated, the labels you've added will also be deallocated.
When you are using ARC (Automatic Reference Counting), you should never make any memory management calls because the compiler will insert these statements for you at compile-time.
The compiler should be injecting [tempLabel release]; to the end of your method at compile-time.
However, because you have added the label as a subview to a view, the containing view will retain the label, and the label will not be released until you remove the label from that view.