Why does this only work sometimes? (UITextView resign first responder question) - iphone

When a user presses the "SEND"(return) button I want the keyboard to retract and do other stuff like send a message. But it only works SOMETIMES...
Why does this code only work SOMETIMES? I need it to work all the time obviously, but it doesn't.
- (void)textViewDidChange:(UITextView *)inTextView {
NSString *text = myTextView.text;
if ([text length] > 0 && [text characterAtIndex:[text length] -1] == '\n') {
myTextView.text = [text substringToIndex:[text length] -1];
[myTextView resignFirstResponder];
[self sendMessage];
}
}

It only gets called if
([text length] > 0 && [text characterAtIndex:[text length] -1] == '\n')
is true. Is this always the case? Maybe add an NSLog statement outside and inside the state to see if it is indeed true all of the time.

Checking for \n looks bizarre. Why would you do that?

This method is getting passed in a view called inTextView but inside the method you are referring to myTextView and you don't mention where that got set.
I would suggest that you change all the myTextView references to inTextView and see if that resolves the problem as you may be working on a UITextView other than myTextView and seeing your problems because of that.

Related

Confirm UITextview auto-complete

This seems impossible, but maybe someone else has had the same problem.
Is it possible for me to accept an autocomplete programmatically, or in some way get the suggested word that pops up? My problem is that I'm capturing the return/backspace keystroke and then move focus to another textview. When enter/backspace is hit, the textview will ignore the auto-suggested word. It seems that it is only possible to accept an autocompletion by hit space/dot (and return for new row). With this code:
- (BOOL) textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range
replacementText:(NSString *)text {
NSRange textViewRange = [textView selectedRange];
// Handle newrow and backspace.
if(([text length] == 0) && (textViewRange.location== 0) && textViewRange.length==0){
// BACKSPACE KEYSTROKE
[delegate doSomethingWhenBackspace];
return NO;
}else if ([text isEqualToString:#"\n"]){
// RETURN KEYSTROKE
[delegate doSomethingWhenReturn];
return NO;
}
return YES;
}
I tried to programmatically add "space" when the return key is hit but that also ignores the auto-completed word.
else if ([text isEqualToString:#"\n"]){
// Tryin to accept autocomplete with no result.
textview.text = [textview.text stringByAppendingString:#" "];
// RETURN KEYSTROKE
[delegate doSomethingWhenReturn];
return NO;
}
Any suggestions?
Call -resignFirstResponder (i.e. [textView resignFirstResponder]) on the text view or text field which needs to accept autocomplete results: UIKit will change the .text property to include the autocorrected text.
If you want to keep the keyboard up after your first view resigns first responder, pass the firstResponder responsibility onto your next text input view with [anotherTextView becomeFirstResponder].
For backspace and space u can use this condition
if ([[text stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]] length]==0)
{
[delegate doSomethingWhenBackspace];
return NO;
}
I've had a very similar problem, I was making an app that had to read every letter in a text view and I has issues when Autocomplete inserted words because it was saving it as if it was one letter.
you could add each character to an array and then check to see if any are over 1 string in length. Or you could add each character that is put in into an array and then run something like
NSString *string = text;
NSMutableArray *array = [NSMutableArray new];
for (int i=0; i<string.length; i++) {
[array addObject:[string substringWithRange:NSMakeRange(i, 1)]];
}
to add each character individually, by comparing the two arrays you could determine if autocorrect has been used and with what word/s.
Hope this will help.

iPhone cellforrowatindexpath issue two nsarray

Here is my code below:
- (UITableViewCell *)tableView:(UITableView *)tableView1 cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSInteger row = [indexPath row];
NSString *contentForThisRow = nil;
NSString *contentForThisRow2 = nil;
if (mySearchBar.text > 0)
{
contentForThisRow = [self.filteredListContent objectAtIndex:row];
NSInteger noWordIndex = [self.noWords indexOfObject:contentForThisRow];
contentForThisRow2 = [self.enWords objectAtIndex:noWordIndex];
NSLog (#"if success?");
}
else
{
contentForThisRow = [self.noWords objectAtIndex:row] ;
contentForThisRow2 = [self.enWords objectAtIndex:row];
NSLog (#"else success?");
}
static NSString *kCellID = #"cellID";
//standard code here etc for this method..
}
The codes above work perfectly except whenever I have used searchBar to filter and then click on Cancel button in the searchBar or Search button in the keyboard and then when I click on my custom "change" button in the navigationbar, the app crashes.
Before I use searchBar, there show up 4 NSLog after each change like:
2011-08-15 17:21:24.481 Enne1[4750:207] else success?
2011-08-15 17:21:24.483 Enne1[4750:207] else success?
2011-08-15 17:21:24.484 Enne1[4750:207] else success?
2011-08-15 17:21:24.485 Enne1[4750:207] else success?
And when I use searchBar to filter words, there show up also 4 NSLog like this:
2011-08-15 17:19:33.713 E1[4744:207] if success?
2011-08-15 17:19:33.714 E1[4744:207] if success?
2011-08-15 17:19:33.714 E1[4744:207] if success?
2011-08-15 17:19:33.715 E1[4744:207] if success?
But when after I have used searchBar and then cleared the searchText either with Cancel or Search and then click on "change button", there show up only 1 NSLog like this:
2
011-08-15 17:21:49.806 E1[4750:207] if success?
It should be
else success
in order to show the full lists, not
if success
.
Am I missing something?
EDIT 15 august:
I have tried
if(mySearchBar.text.length > 0)
as well, but the tableview shows nothing when I clear my search string and there came up only 2 nslogs, that is:
2011-08-15 23:49:06.624 E1[5064:207] if success?
2011-08-15 23:49:06.626 E1[5064:207] if success?
By the way, why does it show up 4 nslogs each time I enter one alphabet in the search bar? Shouldnt it show only one nslog each time?
And my codes for textDidChange is:
- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchString
{
NSLog (#" ss: %#", searchString);
if ([searchString length] == 0) {
[self performSelector:#selector(hideKeyboardWithSearchBar:) withObject:searchBar afterDelay:0];
NSLog (#" searchstring: %#", searchString);
}
[self filterContentForSearchText:searchString];
[tableView reloadData];
NSLog (#"has reloaded!");
return;
}
Edit 15 august; This is wrong: I suspect the code above is causing the app crashing? not reloading tableview properly?
Am I right? NSLog for searchString showed nothing...
2nd edit 15 august: I added NSLog (#" ss: %#", searchString); and of course it shows alphabet(s) each time I enter one alphabet. So it must be something wrong with mySearchBar.text > 0, how should I write this properly?
By the way, I added tableview and searchbar programmatically, tableviews delegate and datasource is linked to self and searchbars delegate is linked to self as well. There is nothing in InterfaceBuilder, only UIView.
Not really sure what you're attempting with
if(mySearch.text > 0) {
//stuff
}
Looks, like you're trying to compare the length to see if the string is empty. Try using this instead:
if([mySearchBar text] == nil || ![[mySearchBar text] isEqualToString:#""]) {
//stuff
}
Getting into this code block is probably what the problem is. Not sure how your objects are implemented, but if the filtered list is nil, then you would crash trying to get objects from it and what not.
You should definitely use if(mySearchBar.text.length > 0), not if(mySearchBar.text > 0).
It probably crashes here:
contentForThisRow2 = [self.enWords objectAtIndex:noWordIndex];
because noWordIndex was -1 (i.e. 2147483647) in the previous line. It'll crash this way even if you just type in a word that doesn't exist in the noWords array, so you need to check if noWordIndex is >= 0 before using it to access enWords. This will probably fix the problem with cleaning the search text, too.
By the way, a much faster way to look up words would be using an NSDictionary instead of two arrays.
Ah, I solved it by adding length to mySearchBar.text; mySearchBar.text.length > 0 works. I forgot to rewrite in another method, I changed mySearchBar.text to mySearchBar.text.length, that is:
- (NSInteger)tableView:(UITableView *)tableView1 numberOfRowsInSection:(NSInteger)section
{
tableView1.rowHeight = 100 ;
tableView1.separatorColor = [UIColor colorWithRed:0.40 green:0.70 blue:0.45 alpha:1.0];
tableView1.opaque = NO;
if (mySearchBar.text.length > 0)
{
return [self.filteredListContent count];
NSLog (#"if return");
}
else
{
return [self.noWords count];
NSLog (#"else return");
}
}
#Daniel R Hicks
and
#ColdLogic: So both you are right that it is wrong to use only mySearchBar.text. Thank you very much for pointing me in the right direction.
But I still wonder why there come up 4 nslogs each time...
EDIT 16 august:
4 nslogs show up every time I launch the app, because there are 4 visible cells. My tableview.height is 100, so when I changed it to 50, 8 nslogs show up and as well as 8 visible cells.

How to test a UITextField for being nil?

I am trying to make a part of my app where if the person doesn't change the blank text in my UITextField, then he/she can't go on to the next step. Basically, I want to test the UITextField for nil text. I have used the if (text == #"") method, but if the person clicks on the UITextField but doesn't type, then the if statement doesn't work. For some reason it doesn't think the text == nil or "". Am I implementing the code wrong. Any other options. Please help!!!
You should be checking the length of the text property:
if([[textField text] length] == 0) {
//do something...
}
Here's the category I use...
#implementation NSString (NSString+Extensions)
- (BOOL)isNotBlank {
return [[self stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] length] > 0;
}
#end
This way a nil string would evaluate to false, which is correct. Creating an isBlank would return false for nil, which isn't correct.
I have write code to check the string is empty or not. This code also check for the string only space that is also empty for store name and address etc. this will help you.
NSString *stringTemp = textField.text;
stringTemp = [stringTemp stringByReplacingOccurrencesOfString:#" " withString:#""];
if ([stringTemp isEqualToString:#""]) {
NSLog(#"Empty string");
}
else{
NSLog(#"string has some content ");
}
Thanks
If I were you I would disable and enable the button while the user is typing. Imho it's better that the button looks disabled when there is no text than having the user click the button to tell him that he is not allowed to move to the next view. Most of apples own apps do it like this.
You achieve this behavior by using the UITextFieldDelegate method like this
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
// "Length of existing text" - "Length of replaced text" + "Length of replacement text"
NSInteger textLength = [aTextView.text length] - range.length + [text length];
if (textLength > 0) {
doneButton.enabled = YES;
}
else {
doneButton.enabled = NO;
}
return YES;
}
If you provide a prefilled textfield you have to enable the button in viewDidLoad (or where ever you want) and if you provide an empty field you have to disable it initally.

becomeFirstResponder on UITextView not working

For some reason, I'm having trouble with making a textfield the first responder.
I have a UITableView with two rows. Each row has a label and a UITextField. The textfields are tagged kLoginRowIndex = 0 and kPasswordRowIndex = 1. As you might have guessed, I use this for setting login and password.
If the user taps on the return button when editing the login textfield, I want the password textfield to get the focus. Unfortunately, the password textfield doesn't accept the focus. Here is my code:
- (BOOL)textFieldShouldReturn:(UITextField *)textField {
NSLog(#"%s:(textField.tag:%d)", __FUNCTION__, textField.tag);
[textField resignFirstResponder];
if(textField.tag == kLoginRowIndex) {
UITableViewCell *cell = [self tableView:self.tableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:kPasswordRowIndex inSection:0]];
UITextField *nextTextField = (UITextField *)[cell viewWithTag:kPasswordRowIndex];
NSLog(#"(nextTextField.tag:%d)", nextTextField.tag);
NSLog(#"canBecomeFirstResponder returned %d", [nextTextField canBecomeFirstResponder]);
NSLog(#"becomeFirstResponder returned %d", [nextTextField becomeFirstResponder]);
} else {
[self validate:textField];
}
return NO;
}
This is the log output:
-[SettingsViewController textFieldShouldReturn:]:(textField.tag:0)
(nextTextField.tag:1)
canBecomeFirstResponder returned 1
becomeFirstResponder returned 0
What I tried:
returning YES instead of NO
removing the call to canBecomeFirstResponder (which is just for debugging purposes)
Any hints are appreciated!
After playing with the suggestion of tmadsen, I found the error. The mistake is this line:
UITableViewCell *cell = [self tableView:self.tableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:k
It returns a new cell, not the one currently on the screen. I replaced it with
UITableViewCell *cell = [self.tableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:kPasswordRowInde
and now it works as expected.
On a side note, I found out that 0 is the default value for the tag property, so it's probably not so clever to use it.
0 is the default value for the tag property so you'll probably want to use something other than 0, otherwise you will most likely return the superview when you call viewWithTag:
It's been a while since I developed for the iPhone, and I have never used the tag that you show in your code. But you can do what you want by making the textfields properties of your class. If you do that, and let's say you name those properties loginTextField and passwordTextField, then you can let the next textField be focused as follows:
- (BOOL)textFieldShouldReturn:(UITextField *)textField {
if([self usernameTextField] == textField) {
return [[self passwordTextField] becomeFirstResponder];
}
else {
// your validating code...
}
return NO;
}
But as I said, it's been a while and I don't know this tag-thing you talk about, so maybe it's some new best practice, but the above code should be working

UITextField text value returns garbage

I am trying to get a string value out of a textField when the user dismisses the keyboard. However, it seems that whenever I try to get the value, I get garbage (attempting to print out textField.text gives out garbage). What could I be doing wrong?
(The control displays fine, and I can put text values into it even).
Here's my code:
-(BOOL)textFieldShouldReturn:(UITextField *)textField {
NSInteger currenttag = textField.tag;
NSLog(#"%d",textField.tag);
if (currenttag == 0) {
NSLog(#"%x %s",(unsigned int)textField.text,textField.text);
username = textField.text;
} else if (currenttag == 1) {
password = textField.text;
}
[textField resignFirstResponder];
return YES;
}
The fields username and passwords are nil NSString*'s, but since I will merely hold on to the NSStrings held by textField.text, it should be fine.
NSLog(#"text field text:%#",textField.text);
Have you tried using breakpoints? Have you tried NSLog(#"%#", textField.text); ?
Have you tried rewriting the function so it only displays the text?
Is the textField a valid object?
Inserting [textField retain]; as the 1st line will probably fix the problem. Just remember to add a [textField release]; at the end of the method.