I'm an absolute beginner, and I need to have a button to invert two text fields:
text1 <—> text2
- (IBAction)swapText {
name.text = surname.text;
surname.text = name.text;
}
I know that I have to retain the values and then release them, but I'm not sure how to write it.
This is quite simple: the only text / NSString you have to retain is the one that will stop being hold by the UITextField itself, namely the name.text that you will replace by surname.text.
- (IBAction)swapText {
NSString* temp = [name.text retain];
name.text = surname.text;
surname.text = temp;
[temp release];
}
The only objects you need to take care of would be alloc/deallocating the UITextFields. Assuming your UITextfields are ivars (declared in your header file) you can use the following code:
- (void)viewDidLoad
{
[super viewDidLoad];
CGRect b = [[self view] bounds];
_txt1 = [[UITextField alloc] initWithFrame:CGRectMake(CGRectGetMidX(b)-100, 50, 200, 29)];
[_txt1 setBorderStyle:UITextBorderStyleRoundedRect];
[[self view] addSubview:_txt1];
_txt2 = [[UITextField alloc] initWithFrame:CGRectMake(CGRectGetMidX(b)-100, 100, 200, 29)];
[_txt2 setBorderStyle:UITextBorderStyleRoundedRect];
[[self view] addSubview:_txt2];
UIButton* btnSwap = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[btnSwap setFrame:CGRectMake(CGRectGetMidX(b)-75, 150, 150, 44)];
[btnSwap setTitle:#"Swap Text" forState:UIControlStateNormal];
[btnSwap addTarget:self action:#selector(tappedSwapButton) forControlEvents:UIControlEventTouchUpInside];
[[self view] addSubview:btnSwap];
}
- (void)tappedSwapButton
{
NSString* text1 = [_txt1 text];
NSString* text2 = [_txt2 text];
[_txt2 setText:text1];
[_txt1 setText:text2];
}
- (void)dealloc
{
[_txt1 release];
[_txt2 release];
[super dealloc];
}
Based on your code given, your text in the first textfield will be lost. The easiest way to fix that is to declare a temp NSString object that will hold the string that is contained in name.text:
- (IBAction)swapText{
// create a temp string to hold the contents of name.text
NSString *tempString = [NSString stringWithString: name.text];
name.text = surname.text;
surname.text = tempString;
}
Since you are using dot notation, it is assumed that "name" and "surname" are properties for the IBOutlet references to both textfields that you want to swap. If this is the case, as long as you have "retain" for both of these properties, that will take care of the memory management (as long as you release these in the dealloc method in the .m file).
Related
Ok simple question but can't find an answer.
I'v got a button to save information in my app.
I have
NSMutableArray *textFields = [[NSMutableArray alloc] initWithCapacity:5];
UITextField *textField = nil;
This is the information i want to save, i'v got 5 textfields in textFields mutablearray.
[save addTarget:self action:#selector(saveInfo)
forControlEvents:UIControlEventTouchUpInside];
and
-(void)saveInfo {
[[[NSUserDefaults standardUserDefaults] setValue: ????? forKey:#"Phone"];
[[NSUserDefaults standardUserDefaults] synchronize];
}
The question is how to access and get information from like textFields[1].text in my saveInfo void ?
Ok To get things a little bit clearer i'v added the whole class. its not very big, and maybe someone could see thats the problem with my implementation .
#implementation Settings
- (id)init: (TableViewController*) TableControll {
NSMutableArray *textFields = [[NSMutableArray alloc] initWithCapacity:5];
UITextField *textField = nil;
for (int i = 0; i < 3; i++) {
textField = [[UITextField alloc] initWithFrame:CGRectMake(0.0f, 0.0f+(i*35), 120.0f, 30.0f)];
textField.backgroundColor = [UIColor whiteColor];
[textField setBorderStyle:(UITextBorderStyleRoundedRect)];
[TableControll.view addSubview:textField];
[textFields addObject:textField];
[textField release]; textField = nil;
}
UITextField *textName = textFields[0];
textName.placeholder = #"Vardas";
UITextField *textNo = textFields[1];
textNo.placeholder = #"Telefonas";
textNo.keyboardType = UIKeyboardTypeNumberPad;
UITextField *textPin = textFields[2];
textPin.keyboardType = UIKeyboardTypeNumberPad;
textPin.placeholder = #"Pin";
UIButton *button = [UIButton buttonWithType:UIButtonTypeRoundedRect];
button.frame = CGRectMake(150, 20, 160, 30);
[button setTitle:#"Advanced settings" forState:UIControlStateNormal];
[TableControll.view addSubview:button];
UIButton *save = [UIButton buttonWithType:UIButtonTypeRoundedRect];
save.frame = CGRectMake(150, 60, 160, 30);
[save setTitle:#"Save settings" forState:UIControlStateNormal];
[TableControll.view addSubview:save];
[button addTarget:self action:#selector(goAdvanced)
forControlEvents:UIControlEventTouchUpInside];
[save addTarget:self action:#selector(saveInfo)
forControlEvents:UIControlEventTouchUpInside];
return self;
}
-(void)goAdvanced {
AppDelegate *newControll = (AppDelegate*)[UIApplication sharedApplication].delegate;
[newControll ChangeController];
}
-(void)saveInfo {
for(int i=0;i<5;i++) {
UITextField *tempTxtField=[_textFields objectAtIndex:i];
NSLog(#"do it %#",tempTxtField.text);
}
}
#end
What you'd want to do if you are using interface builder is create a bunch of IBOutlet for your textfields instead of keeping them in an array. Check out this: tutorial
Now it looks like you're creating things by hand, so in this case, you probably just want to declare your array as #property so it can be accessed by your save method.
To access the text property of a UITextField from your array you would write:
((UITextField *)[textFields objectAtIndex:1]).text
If you want to access the all textfield,
for(int i=0;i<[textFields count];i++) {
UITextField *tempTxtField=[textFields objectAtIndex:i];
NSlog(#"%#",tempTxtField);
}
-(void)saveInfo {
NSMutableArray *tempArr = [NSMutableArray array];
for(int i = 0; i < [textFieldsArray count]; i++){
[tempArr addObject:[(UITextField*)[textFieldsArray objectAtIndex:i]text]];
}
[[[NSUserDefaults standardUserDefaults] setValue:tempArr forKey:#"Phone"];
[[NSUserDefaults standardUserDefaults] synchronize];
}
I'm not entirely sure I understand your question, but this is what I would do in your place. Instead of creating an array to hold each of the textfields, I'd just assign them a custom tag. Any number will work (although avoid zero since that's the default tag on all views). So your init method would look like this:
for (int i = 0; i < 3; i++) {
textField = [[UITextField alloc] initWithFrame:CGRectMake(0.0f, 0.0f+(i*35), 120.0f, 30.0f)];
textField.backgroundColor = [UIColor whiteColor];
textField.tag = (i+1);
[textField setBorderStyle:(UITextBorderStyleRoundedRect)];
[TableControll.view addSubview:textField];
[textField release]; textField = nil;
}
Then in the code that you want to reference the text field, you'd retrieve the view by its tag, making sure to cast it as UITextField.
-(void)saveInfo {
for(int i=0;i<5;i++) {
UITextField *textField = nil;
UIView *view = [self.view viewsWithTag:i];
if ([view isKindOfClass:[UITextField class]]) {
textField = (UITextField *) view;
NSLog(#"do it %#",textField.text)
}
}
}
NOTE: I'm referencing self.view but you'll need to reference TableControll.view. You'll need to retain a reference to it somewhere in your code. Also, I'd recommend your start using ARC.
Hope that helps! Good luck!
Ok simple question but can't find an answer..
I need to pass my viewcontroller to an method "saveinfo" within a class which is called when the button is pressed, how to make viewcontroller visible to "saveinfo" method so i can use it there?
Ok i'll add the whole class. Basicaly I need to get the textfield information when the button is pressed. But i can't get access to textFields nor TableControll variables in my saveinfo method.
#implementation Settings
- (id)init: (TableViewController*) TableControll {
NSMutableArray *textFields = [[NSMutableArray alloc] initWithCapacity:5];
UITextField *textField = nil;
for (int i = 0; i < 3; i++) {
textField = [[UITextField alloc] initWithFrame:CGRectMake(0.0f, 0.0f+(i*35), 120.0f, 30.0f)];
textField.backgroundColor = [UIColor whiteColor];
[textField setBorderStyle:(UITextBorderStyleRoundedRect)];
[TableControll.view addSubview:textField];
[textFields addObject:textField];
[textField release]; textField = nil;
}
UITextField *textName = textFields[0];
textName.placeholder = #"Vardas";
UITextField *textNo = textFields[1];
textNo.placeholder = #"Telefonas";
textNo.keyboardType = UIKeyboardTypeNumberPad;
UITextField *textPin = textFields[2];
textPin.keyboardType = UIKeyboardTypeNumberPad;
textPin.placeholder = #"Pin";
UIButton *button = [UIButton buttonWithType:UIButtonTypeRoundedRect];
button.frame = CGRectMake(150, 20, 160, 30);
[button setTitle:#"Advanced settings" forState:UIControlStateNormal];
[TableControll.view addSubview:button];
UIButton *save = [UIButton buttonWithType:UIButtonTypeRoundedRect];
save.frame = CGRectMake(150, 60, 160, 30);
[save setTitle:#"Save settings" forState:UIControlStateNormal];
[TableControll.view addSubview:save];
[button addTarget:self action:#selector(goAdvanced)
forControlEvents:UIControlEventTouchUpInside];
[save addTarget:self action:#selector(saveInfo)
forControlEvents:UIControlEventTouchUpInside];
return self;
}
-(void)goAdvanced {
AppDelegate *newControll = (AppDelegate*)[UIApplication sharedApplication].delegate;
[newControll ChangeController];
}
-(void)saveInfo {
for(int i=0;i<5;i++) {
UITextField *tempTxtField=[_textFields objectAtIndex:i];
NSLog(#"do it %#",tempTxtField.text);
}
}
#end
just add the NSMutableArray as ivar to your class:
#implementation TableControll {
NSMutableArray *_textFields;
}
- (id)init: (TableViewController*) tableControll {
_textFields = [[NSMutableArray alloc] initWithCapacity:5];
//init the textfields
//and add it as subview
}
// skipping the rest of the implementation
-(void)saveInfo {
for(int i=0;i<5;i++) {
UITextField *tempTxtField=[_textFields objectAtIndex:i];
NSLog(#"do it %#",tempTxtField.text);
}
}
#end
you should check if you could reuse the UITextFields or have to init the NSMutableArray every time again. It seems you don't use ARC, but you shouldn't write something like [textField release]; textField = nil;. You want to release the object to decrement the counter, but do not set it to nil (except in dealloc).
If the user provides a number, such as 8, how exactly would I place eight labels onto the view?
For example:
int userGivenNumber = textfield.text;
for (int labelNumber=1; i<=userGivenNumber; i++) {
UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(50, *previousLabel*.frame.origin.y + 20)];
}
How would you get the location of previousLabel? Additionally, if the user wanted to edit a label, such as label 3, how would I edit this label?
The problem is that I don't know how many labels they want to place while coding, and I have no way of keeping track of the labels, since they are called label. Do you have any ideas? Do you understand what I am asking? Thanks for your help.
- (void)addLabels {
CGFloat offset = 0;
// labels is NSMutableArray property
labels = [[NSMutableArray alloc] initWithCapacity:8];
for (int i = 0; i < 8; i++) {
UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(0, offset, 320, 20)];
[self.view addSubview:label];
[labels addObject:label];
offset += label.frame.size.height;
}
}
Edit: Like jerrylroberts said, to access the label array from elsewhere in your code, you should declare it as a property.
So you could add the views like so:
int userGivenNumber = [textfield.text intValue];
for (int labelNumber=1; i<=userGivenNumber; i++) {
UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(50, *previousLabel*.frame.origin.y + 20)];
[self.view addSubview:label];
[label release];
}
If you wanted to keep track of them you could just create a mutable array as a property and then add each label to the array before you add to the subview;
Interface
#property (nonatomic, retain) NSMutableArray *addedLabels;
Implementation
#synthesize addedLabels=_addedLabels;
- (void)viewDidLoad
[super viewDidLoad];
// Create your array to hold labels
NSMutableArray *addedLabels = [[NSMutableArray alloc] initWithCapacity:0];
self.addedLabels = addedLabels;
[addedLabels release];
// NOW put your code
int userGivenNumber = [textfield.text intValue];
for (int labelNumber=1; i<=userGivenNumber; i++) {
UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(50, *previousLabel*.frame.origin.y + 20)];
[self.view addSubview:label];
[addedLabels addObject:label];
[label release];
}
}
Now you can easily access any label you have added if you have the index. Hope this helps
Just keep a reference to the location (CGPoint) outside the loop, but update it inside the loop to the current label's location. When you assign the next frame do your operation depending on width and size of the label, and don't forget to update the reference of CGPoint.
The pointer passed into the "menuItem" methode is alloc and for the "Pointer Inside" a value is registered. But for the "Pointer Outside" the value is "null" ... why? I passed in the pointer and it should had been modified in the method?
In the header file:
UIButton *bMenu_time;
UILabel *lMenu_time;
Implementation:
- (void) menuItem: (UIView*)vMenu menuButton:(UIButton*)bMenu menuLabel: (UILabel*)lMenu menuPosX: (double)posX menuLenX: (double)lenX menuTagNum: (int)tagNum menuText: (NSString*)txtMenu{
bMenu = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[bMenu setFrame:CGRectMake(posX,0,lenX,25)];
[bMenu setTag: tagNum];
[bMenu addTarget:pSelf action:#selector(NewNumber:) forControlEvents:UIControlEventTouchUpInside];
[vMenu addSubview:bMenu];
lMenu = [[UILabel alloc] initWithFrame:CGRectMake(posX,0,lenX,25)];
[lMenu setBackgroundColor:[UIColor lightGrayColor]];
[lMenu setText:[NSString stringWithFormat: txtMenu]];
[lMenu setFont:[UIFont systemFontOfSize:14 ]];
[lMenu setTextAlignment:UITextAlignmentCenter];
[vMenu addSubview: lMenu];
NSLog(#"\nPointer Inside: %#\n", lMenu); // <--------- INSIDE WORKS
}
- (void) menuBuild{
pSelf = self;
theString = #"";
vMenu = [[UIView alloc] initWithFrame:CGRectMake(0,0,320,25)];
[pSelf.view addSubview:vMenu];
[vMenu setBackgroundColor:[UIColor grayColor]];
iTime = 2;
[self menuItem:vMenu menuButton:bMenu_time menuLabel:lMenu_time menuPosX:240+20 menuLenX:60 menuTagNum:102 menuText:[NSString stringWithFormat: #"Hold: %d", iTime]];
NSLog(#"\nPointer Outside: %#\n", lMenu_time); // <----- OUTSIDE is NULL ??
}
Objective C, like C, is pass by value. That means, if you want to change a pointer by passing it to a function, you need to pass a pointer to the pointer and use that.
In C, that would be something like:
void alloc128 (void **ptr) {
*ptr = malloc (128);
}
Mapping that to your specific case, you can:
modify menuBuild to pass the address of the things you want to change.
modify the function to receive the pointer-to-pointer values.
modify the function to dereference the pointer-to-point values to set them correctly.
paxdiablo is absolutely right, but in case you're uncertain of the syntax for pass-by-reference, here is what your code should be:
- (void) menuItem: (UIView*)vMenu menuButton:(UIButton **)bMenu menuLabel: (UILabel **)lMenu menuPosX: (double)posX menuLenX: (double)lenX menuTagNum: (int)tagNum menuText: (NSString*)txtMenu{
*bMenu = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[*bMenu setFrame:CGRectMake(posX,0,lenX,25)];
[*bMenu setTag: tagNum];
[*bMenu addTarget:pSelf action:#selector(NewNumber:) forControlEvents:UIControlEventTouchUpInside];
[vMenu addSubview:*bMenu];
*lMenu = [[UILabel alloc] initWithFrame:CGRectMake(posX,0,lenX,25)];
[*lMenu setBackgroundColor:[UIColor lightGrayColor]];
[*lMenu setText:[NSString stringWithFormat: txtMenu]];
[*lMenu setFont:[UIFont systemFontOfSize:14 ]];
[*lMenu setTextAlignment:UITextAlignmentCenter];
[vMenu addSubview: *lMenu];
NSLog(#"\nPointer Inside: %#\n", *lMenu); // <--------- INSIDE WORKS
}
- (void) menuBuild{
pSelf = self;
theString = #"";
vMenu = [[UIView alloc] initWithFrame:CGRectMake(0,0,320,25)];
[pSelf.view addSubview:vMenu];
[vMenu setBackgroundColor:[UIColor grayColor]];
iTime = 2;
[self menuItem:vMenu menuButton:&bMenu_time menuLabel:&lMenu_time menuPosX:240+20 menuLenX:60 menuTagNum:102 menuText:[NSString stringWithFormat: #"Hold: %d", iTime]];
NSLog(#"\nPointer Outside: %#\n", lMenu_time); // <----- OUTSIDE is NULL ??
}
Things to note:
objects passed by reference in the method parameters use **
to pass the address of an object to one of these parameters, use &object when calling the method
to refer to an object that is passed by reference, prefix the variable with *
Have a look at how iOS uses error parameters in methods like NSString initWithContentsOfFile:error: for more examples of how this approach is used.
Unable to change text in lMenu_time (this is a UILabel) after it was initially set.
The call back is executed, I tested this, but the text won't change.
?? I am passing around the pointer and making adjustments to the UILabel. ??
lMenu_time and numerous others are defined in the header file. (not seen here)
UILabel *lMenu_time;
...
-(void) NewNumber: (UIButton*) btn {
if (btn.tag == 102){
iTime++;
[lbl setText:#"time"];
if(iTime > 20){iTime=1;}
[lMenu_time setText:[NSString stringWithFormat: #"Hold: %d", iTime]];
}
....
}
- (void) menuItem: (UIView*)vMenu menuButton:(UIButton*)bMenu menuLabel: (UILabel*)lMenu menuPosX: (double)posX menuLenX: (double)lenX menuTagNum: (int)tagNum menuText: (NSString*)txtMenu{
bMenu = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[bMenu setFrame:CGRectMake(posX,0,lenX,25)];
[bMenu setTag: tagNum];
[bMenu addTarget:self action:#selector(NewNumber:) forControlEvents:UIControlEventTouchUpInside];
[vMenu addSubview:bMenu];
lMenu = [[[UILabel alloc] initWithFrame:CGRectMake(posX,0,lenX,25)] retain];
[lMenu setBackgroundColor:[UIColor lightGrayColor]];
[lMenu setText:[NSString stringWithFormat: txtMenu]];
[lMenu setFont:[UIFont systemFontOfSize:14 ]];
[lMenu setTextAlignment:UITextAlignmentCenter];
[vMenu addSubview: lMenu];
}
- (void) menuBuild{
pSelf = self;
theString = #"";
UIView *vMenu = [[UIView alloc] initWithFrame:CGRectMake(0,0,320,25)];
[pSelf.view addSubview:vMenu];
[vMenu setBackgroundColor:[UIColor grayColor]];
iTime = 2;
[self menuItem:vMenu menuButton:bMenu_time menuLabel:lMenu_time menuPosX:240+20 menuLenX:60 menuTagNum:102 menuText:[NSString stringWithFormat: #"Hold: %d", iTime]];
...
}
Just before you try to set the next, try adding
NSLog(#"My label is %#",lMenu_time);
Then, if your console outputs "My label is (nil)" you'll know that the problem is that the pointer to lMenu_time isn't being passed around properly.
Did you bind the label object to the controller in Interface builder? If not I would bet this is an retention issue. You do not post the code that builds the UILabel object, so if that is not done in IB, ensure you call retain or it will certainly be out of scope when you try and modify it.