UITextField - [textField becomesFirstResponder] - remember text - iphone

NSString *tmpTxt = textField.text;
BOOL result = [textField becomeFirstResponder];
textField.text = tmpTxt;
This works 80% of the time, but occasionally:
The whole app will crash.
The text will still be deleted whatever happens.
Whats the best way for a textField to becomeFirstResponder and still retain its text value.

If its clearing when it becomesFirstResponder, I guess is that you have #property(nonatomic) BOOL clearsOnBeginEditing set to YES.
Maybe, where ever you care creating textField, add textField.clearsOnBeginEditing = NO ;
If you are using interface builder there is a check box in the properties for the textfield.
As to why its crashing most of the time...
the text property is defined as: #property(nonatomic, copy) NSString *text
The copy means when you assign a value to it, it will release the previous value, and then make a copy of the value passed in.
Your first line you are keeping a pointer around of the NSString object without calling retain on it. So when you call becomeFirstResponder with clearsOnBeginEditing is called it will set the new value to an empty NSString, which will release the old NSString that the UITextField had reference to. Since its the only thing that had ownership of it, that release call will call dealloc on the NSString, invalidating it.
Then you reassign it back to the text property where it attempts to copy the object that has been freed.
So to do it the way you have it, you will need to call retain and release:
NSString *tmpTxt = [textField.text retain];
BOOL result = [textField becomeFirstResponder];
textField.text = tmpTxt;
[tmpTxt release];
However all you need to do is set clearsOnBeginEdit to NO and you won't need that code.

Related

REAL DIFFERENCE between self.text and _text [duplicate]

This question already has an answer here:
What's the difference between _variable & self.variable in Objective-C? [duplicate]
(1 answer)
Closed 9 years ago.
i read a lot of post about this subject, yet i can't understand everything completely.
Ok, it's clear that
self.text = #"MyText" will call the accessory method setText (autogenerated)
_text = #"MyText" will still assign the value but will not call the setText
This is clear.
But this can be useful when we are not using ARC beacuse setText will take care of the memory management. But what happen when we are using ARC?
Sometimes if i am using _text everything works fine, some other time my application won't work if i wont use "self.text".
So what is the the real difference? There must be something more than memory management.
let's say i have this
#interface MyClass:NSObject {
NSMutableString *text;
}
#property (nonatomic ) NSMutableString *text;
in this case isn't it the same calling
self.text = #"ok"
or
text = #"ok" ?
what's the difference?
The underlying instance variable for that property is in fact _text. That is how auto synthesised properties work.
However you should consider using the accessors to set the property (using self. text = instead). See this link for more info on Reason to use ivars vs properties in objective c
self.text is syntactic sugar for [self text] (or [self setText:...], if on the left side of the assignment), and is a message; when it is autogenerated ("synthesised"), it will return the value of the connected instance variable. _text is this instance variable.
You can only access an instance variable within the class. You can send a message from anywhere. This distinction is important in case that one day you wish to modify the inner working of the text attribute so that it does not simply return the value of the local variable.
the answer is here really Do I need variable and property at the same time?
When you #property you're actually creating methods for accessing and mutating as well as an instance variable.
So when you have #property (nonatomic, strong) NSString *text; you create an iVar _text and two methods:
self.text; //will call -(NSString *)text;
self.text = #"text here"; //is calling -(void)setText:(NSString *)text;
#property is used to strip down boiler plate code, it reduces the number of lines of code required for you to write your classes.
Sure sometimes calling self.text = #"ok" and _text = #"ok" is alright in an ARC environment nowdays, but you don't get the -(NSString *)text; and -(void)setText:(NSString *)text; in your public header file.
Also, its often good practise to call self.text and self.text = or their equivalents [self text] [self setText:] as you might have overridden the text implementations:
-(NSString *)text{
return [NSString stringWithFormat#"%#.jpg", _text];
}
-(void)setText:(NSString *)text{
_text = [NSString stringWithFormat:#"DW%#", text];
}
So when you do this:
self.text = #"HelloThere";
NSLog (#"%#", self.text); //This will return DWHelloThere.jpg
NSLog (#"%#", _text); //Will return DWHelloThere
//whereas
_text = #"HelloThere";
NSLog (#"%#", _text); //Will return HelloThere
So #property can save you about 8 lines of code, keeps your own classes nice and tidy, and if need be you can override the accessors and mutators. But because of the latter point its good practise to call self.text and self.text = #"so and so" rather than just accessing the iVar by itself.
Conceptually, the difference is only that in one case a message is sent to the object or a single ivar is changed in the other. The memory management story is just a necessary house keeping that is handled for you by ARC if you use it.
If you are interested in the moral story, then read Jon Reid's post here: Dot Notation in Objective-C: 100% Pure Evil http://qualitycoding.org/dot-notation/
Side note: Whenever you can, use ARC. It will take care of the retain-release cycle automatically in most cases correctly (accessing self in blocks should be handled with care, though.) If you use ARC there is no difference between the two methods, the retain count will be handled correctly. And as you described, without ARC, you must make sure that after the property setting, the object must be released, while this is not necessary when the ivar is accessed. More on some practices is described in this post: Properties and Memory Management in Objective-C http://www.whilethis.com/2011/04/properties-and-memory-management-in-objective-c/
the real difference is that:
when you create your instance in your code you have a variable called text.
when instead you use the property on text, it will create an iVar called _text.
as you can imagine, calling one or another, will be a big difference since they are 2 totally different variables
self.text = #"Something" accesses to you private variable _text using accessor method [self setText:#"Something"]. The dot notation is just a syntactic sugar. This method can have its own implementation adding extra functionality to just setting value of private variable _text.
_text = #"Something" sets the value to the private variable itself directly.
Also, when setting text property's value outside the class implementation, the accessor [instance setText:#"Something"] is called automatically to set the value of private variable
Let me show you simple example what could be difference. The method implementation is simple just for educational purposes, so it may not make sense in real code :-)
Imagine you want to log a message to the console every time the value of text property changes. You can accomplish this by overriding the accessor method - (void)setText:(NSString *)text like this for example:
- (void)setText:(NSString *)text
{
// You can do whatever you want with the input "text" value, validate the value for example
// Here we just log the text was changed
// In the log message, we still have the old value of the "text" in the private variable "_text"
// so we can log it together with the new value
NSLog(#"Value of \"text\" property changed from \"%#\" to \"%#\"", _text, text);
// Set the new value of the private variable
_text = text;
// From here on, the private variable already has new value and the log line above
// would give the same values between from and to quotes
NSLog(#"Value of \"text\" property is now \"%#\"", _text);
}
So when you set the _text directly, none of the log messages above would be performed, because you access the variable directly.
On the other hand, setting using accessor method self.text = #"Something" would cause following to be printed out to the console:
Value of "text" property changed from "(null)" to "Something"
Value of "text" property is now "Something"

Calling a method in another method?

I've got a delegate method which just has a bit of code in there that puts a % sign on the end of the number entered.
- (void)textFieldDidEndEditing:(UITextField *)UItextfield {
NSString *oldTextFieldValue = UItextfield.text;
UItextfield.text = [NSString stringWithFormat:#"%# %%",oldTextFieldValue];
}
Could I instead of having that, have the following action
-(IBAction)Calculate:(UITextField *)UITextfield;
{
NSString *oldTextFieldValue = UItextfield.text;
UItextfield.text = [NSString stringWithFormat:#"%# %%",oldTextFieldValue];
}
And then in the Delegate function, call that action? Something like
-(void)textFieldDidEndEditing:(UITextField *)UItextfield {
[self Calculate:self]
}
I tried that, it doesn't work. I know it'll get me to the same result but I just want to know if it can be done. I think i'm asking can a method (Calculate) be called in another method (textFieldDidEndEditing) and how.
You are providing self as the method argument which is the instance of the class you are in. Which in this case is wrong since the method argument should be an instance of UITextField. Try instead [self Calculate:UItextfield] in your method.
Calling other methods from methods happen all the time in most programming languages.
It's a great way to split code up and reuse code in different places without having to copy/paste.
(This might be too basic for you. Sorry in that case)
Things may be easier to understand if you use standard naming conventions too. ('likeThis' for variables and method names; 'LikeThis' for class names)
- (void)textFieldDidEndEditing:(UITextField *)textField {
NSString *oldTextFieldValue = textField.text;
textField.text = [NSString stringWithFormat:#"%# %%",oldTextFieldValue];
}
textField here, is the pointer to the UITextField object which just finished editing.
You want to pass this object to your new 'other' method.
[self calculate:textField];
self is a pointer to an instance of the current class. For example, in a UIViewController subclass called 'MyViewController', self refers to the current instance of this class.
Since the -calculate method is an instance method (beginning with a '-') it requires you to use self. The variable textField is passed after the colon.
- (void)calculate: (UITextField*)textField {
NSString *oldTextFieldValue = textField.text;
textField.text = [NSString stringWithFormat:#"%# %%",oldTextFieldValue];
}
Use only the IBAction keyword when you want the method to be called from a UIComponent in an xib or storyboard.

creating a Mutable array that can be added to in later clicks of the same button?

General noob questions:
(1) How can I create an NSMutable array in a buttonClicked action that I can add more entries to during subsequent clicks of the same button? I always seem to start over with a new array at every click (the array prints with only 1 entry which is the most recent button's tag in an NSLog statement).
I have about 100 buttons (one for each character in my string called "list") generated by a for-loop earlier in my code, and each has been assigned a tag. They are in a scrollview within the view of my ViewController.
I wish to keep track of how many (and which ones) of the buttons have been clicked with the option of removing those entries if they are clicked a second time.
This is what I have so far:
-(void) buttonClicked:(UIButton *)sender
NSMutableArray * theseButtonsHaveBeenClicked = [[NSMutableArray alloc] initWithCapacity: list.length];
NSNumber *sendNum = [NSNumber numberWithInt:sender.tag];
[theseButtonsHaveBeenClicked addObject:sendNum at index:sender.tag];
NSLog(#"%#",theseButtonsHaveBeenClicked);
}
(2) I have read that I may be able to use a plist dictionary but I don't really understand how I would accomplish that in code since I cant type out the items in the dictionary manually (since I don't know which buttons the user will click). Would this be easier if I somehow loaded and replaced the dictionary in a plist file? And how would I do that?
(3) I also have no idea how I should memory manage this since I need to keep updating the array. autorelease?
Thanks for any help you can provide!
Okay, firstly you are creating a locally scoped array that is being re-initialised on every call to buttonClicked:. The variable should be part of the class init cycle.
You will also be better off with an NSMutableDictionary instead of an NSMutableArray. With a dictionary we don't have to specify capacity and we can use the button's tags as dictionary keys.
Here's what you need to do, these three steps always go together: property/synthesize/release. A good one to remember.
//Add property declaration to .h file
#property (nonatomic, retain) NSMutableDictionary * theseButtonsHaveBeenClicked;
//Add the synthesize directive to the top of .m file
#synthesize theseButtonsHaveBeenClicked;
// Add release call to the dealloc method at the bottom of .m file
- (void) dealloc {
self.theseButtonsHaveBeenClicked = nil; // syntactically equiv to [theseButtonsHaveBeenClicked release] but also nulls the pointer
[super dealloc];
}
Next we create a storage object when the class instance is initialised. Add this to your class's init or viewDidLoad method.
self.theseButtonsHaveBeenClicked = [[NSMutableDictionary alloc] dictionary]; // convenience method for creating a dictionary
And your updated buttonClicked: method should look more like this.
-(void) buttonClicked:(UIButton *)sender {
NSNumber *senderTagAsNum = [NSNumber numberWithInt:sender.tag];
NSString *senderTagAsString = [[NSString alloc] initWithFormat:#"%#",senderTagAsNum];
// this block adds to dict on first click, removes if already in dict
if(![self.theseButtonsHaveBeenClicked objectForKey:senderTagAsString]) {
[self.theseButtonsHaveBeenClicked setValue:senderTagAsNum forKey:senderTagAsString];
} else {
[self.theseButtonsHaveBeenClicked removeObjectForKey:senderTagAsString]; }
[senderTagAsString release];
NSLog(#"%#", self.theseButtonsHaveBeenClicked);
}

Problem with class methods in objective c

i have a tableview controller like so,
NSString *selectedindex;
#interface ContactsController : UITableViewController<ABPeoplePickerNavigationControllerDelegate> {
NSMutableArray *names;
NSMutableArray *phonenumbers;
NSMutableArray *contacts;
DatabaseCRUD *sampledatabase;
}
+(NSString *) returnselectedindex;
#end
in the implementation file i have
+(NSString *) returnselectedindex
{
return selectedindex;
}
when a row is selected in the tableview i put have the following code.
selectedindex = [NSString stringWithFormat:#"%d", indexPath.row];
NSLog(#"selected row is %#",selectedindex);
in a different class i am trying to access the selectedindex. like so
selected = [ContactsController returnselectedindex];
NSLog(#"selected is %#",selected);
it gives me a warning: 'ContactsController' may not respond to '+returnselectedindex'
and crashes. i am not sure why. i have used class methods previously lot of times , and never had a problem. any help please. Thank You.
The reason you're crashing is that you're assigning a value to a global variable (selectedindex), but you're never taking ownership of it by calling -retain. As a result, the string doesn't know you need it to stay around, so the system deallocates it. Later, when you try to access it, it's already deallocated.
In order to avoid the crash, you need to add a retain call when you assign the value. Of course, since a selected index is something that's likely to be changing often, you'd want to release the previous value before overwriting it and retaining the new one. Thus, you should have this code:
[selectedindex release];
selectedindex = [[NSString stringWithFormat:#"%d", indexPath.row] retain];
That will fix your crash.
Now that your crash is fixed, though, you should really rethink your design. There's no reason for selectedindex to be a global variable; since the selected index is very likely specific to that instance of your ContactsController, it should be an instance variable of that class. Instead, you've declared it as a global variable, which means that there is only one selectedIndex shared between ALL instances of ContactsController. Then, in turn, your +returnselectedindex method should be an instance method, not a class method. (It should also be renamed in order to follow Cocoa naming conventions, but that's well off topic.)
I think You didn't allocated the selectedindex NSString.Thats why it will not crash on the same class and it crashes in the new Class.
So You allocate it in the setter method of "returnselectedindex"
Otherwise, Copy or retain the receive value of returnselectedindex value like this,
selected = [[ContactsController returnselectedindex]copy];

iphone setting UITextView delegate breaks auto completion

I have a UITextField that I would like to enable auto completion on by:
[self.textView setAutocorrectionType:UITextAutocorrectionTypeYes];
This works normally, except when I give the UITextView a delegate. When a delegate is set, auto complete just stops working. The delegate has only the following method:
- (void)textViewDidChange:(UITextView *)textView
{
self.textView.text = [self.textView.text stringByReplacingOccurrencesOfString:#"\n" withString:#""];
int left = LENGTH_MAX -[self.textView.text length];
self.characterCountLabel.text = [NSString stringWithFormat:#"%i",abs(left)];
}
Does anyone know how to have both auto complete enabled and a delegate set?
Thanks!Tristan
It's probably breaking autocompletion because you're simultaneously modifying the text in the UITextView.
NSRange r= [self.textView.text rangeOfString:#"\n"];
if(r.location!=NSNotFound) //must check before replacing new lines right away, otherwise spellcheck gets broken
{
self.textView.text = [self.textView.text stringByReplacingOccurrencesOfString:#"\n" withString:#""];
}
The problem was caused by doing something that potentially modifies the text every time it was changed (ie calling replace method). The solution was to only call the replace method when it was necessary.
Get this: All you need to do is remove UITextViewDelegate from your interface (.h) file.
You can still set the delegate to the textView in the nib.
Odd, right? Worked for me, I hope it would solve your problem as well.