文本字段和文本視圖有兩個(gè)主要的功能:顯示文本宙搬,以及允許輸入和編輯文本饶碘。 很多編程任務(wù)和這些簡單的目標(biāo)相關(guān)聯(lián)目尖,包括配置文本對(duì)象、訪問當(dāng)前文本扎运、檢查用戶的輸入瑟曲、以及顯示覆蓋視圖(例如在文本字段中的書簽按鈕)。
UITextField或者UITextView對(duì)象的委托負(fù)責(zé)處理其中大部分的任務(wù)豪治。這些委托必須采用UITextFieldDelegate或者UITextViewDelegate協(xié)議洞拨,并使其中一個(gè)或多個(gè)方法。所有協(xié)議方法都是可選實(shí)現(xiàn)的负拟。為了能夠調(diào)用這些方法烦衣,你必須用編碼的方式或者Interface Builder設(shè)置文本字段和文本視圖的delegate屬性。
給委托發(fā)送的消息的順序
在大多數(shù)情況下齿椅,UITextField或UITextView類的實(shí)例會(huì)在給定的文本對(duì)象的第一響應(yīng)者狀態(tài)改變的時(shí)候發(fā)送一系列名字類似的信息給它們的委托琉挖。當(dāng)用戶點(diǎn)擊一個(gè)文本對(duì)象启泣,它會(huì)自動(dòng)變成第一響應(yīng)者涣脚;所以系統(tǒng)回味該文本對(duì)象顯示鍵盤并開始一個(gè)編輯會(huì)話。當(dāng)用戶點(diǎn)擊另一個(gè)文本對(duì)象或點(diǎn)擊按鈕來結(jié)束編輯的時(shí)候寥茫,當(dāng)前的文本對(duì)象注銷第一響應(yīng)者狀態(tài)遣蚀。如果沒有其他文本對(duì)象被選擇,系統(tǒng)會(huì)隱藏鍵盤纱耻;另一方面芭梯,如果用戶選擇了另一個(gè)文本對(duì)象,它會(huì)變成第一響應(yīng)者弄喘,并且鍵盤會(huì)為該對(duì)象而存在玖喘。
對(duì)于一般的行為有兩個(gè)例外。在iPad上蘑志,如果視圖控制器使用“form sheet”樣式模態(tài)呈現(xiàn)它的視圖累奈,顯示的鍵盤不會(huì)消失贬派,直到用戶點(diǎn)擊關(guān)閉按鈕或者模態(tài)視圖控制器以編程的方式關(guān)閉。這樣設(shè)計(jì)的目的是避免過多的動(dòng)畫澎媒。另一個(gè)例外是自定義輸入視圖搞乏。輸入視圖可以替代分配給文本視圖或自定義視圖的inputView屬性的系統(tǒng)鍵盤。當(dāng)有輸入視圖的時(shí)候戒努,即使文本對(duì)象是第一響應(yīng)者请敦,UIKit也可以切換鍵盤。
文本視圖和文本字段給它們委托發(fā)送信息的順序如下:
- 在文本對(duì)象剛剛成為第一響應(yīng)者之前——textFieldShouldBeginEditing: (文本字段) 和textViewShouldBeginEditing: (文本視圖)储玫。委托可以通過返回YES(默認(rèn))或NO來校驗(yàn)是否將文本對(duì)象變成第一響應(yīng)者侍筛。
- 在文本對(duì)象剛剛成為第一響應(yīng)者之后——textFieldDidBeginEditing: (文本字段) 和 textViewDidBeginEditing: (文本視圖)。委托可以通過諸如更新狀態(tài)信息或在編輯會(huì)話期間展示覆蓋視圖對(duì)該消息作出響應(yīng)撒穷。
- 在編輯會(huì)話期間——當(dāng)用戶輸入以及編輯文本的時(shí)候勾笆,文本對(duì)象調(diào)用合適的委托方法(如果實(shí)現(xiàn))。例如桥滨,文本視圖可以在文本改變時(shí)候窝爪,它的委托可以接受textViewDidChange:消息。文本字段可以在用于點(diǎn)擊它的清除按鈕的時(shí)候接受textFieldShouldClear: 消息齐媒;委托返回布爾值來說明是否清除文本蒲每。
實(shí)現(xiàn)這些方法是為了輸入文本的有效性。例如喻括,如果文本應(yīng)該遵循給定的格式邀杏,那么在字符串未遵守格式的時(shí)候委托應(yīng)該返回NO。 - 在文本對(duì)象剛剛注銷第一響應(yīng)者之前——textFieldShouldEndEditing: (文本字段) 和 textViewShouldEndEditing: (文本視圖)唬血。實(shí)現(xiàn)這些方法的主要原因是望蜡,驗(yàn)證輸入的文本。例如拷恨,如果文本應(yīng)該符合給定的模式脖律,如果輸入的字符串不符合給定的模式,該委托會(huì)返回NO腕侄。默認(rèn)情況下返回的是YES小泉。
相關(guān)的文本字段的方法是textFieldShouldReturn:。當(dāng)用戶點(diǎn)擊回車鍵的時(shí)候冕杠,文本字段會(huì)發(fā)送textFieldShouldReturn:方法給委托微姊,來詢問它是否應(yīng)該注銷第一響應(yīng)者。 - 在文本對(duì)象剛剛注銷第一響應(yīng)著之后————textFieldDidEndEditing: (文本字段) 和 textViewDidEndEditing: (文本視圖)分预。委托可以實(shí)現(xiàn)這些方法來獲取用戶剛剛輸入或編輯的文本兢交。
文本視圖和文本字段的第一響應(yīng)者狀態(tài)的改變,可以通過觀察通知來通知委托以外的對(duì)象笼痹。(但是配喳,它們不能批準(zhǔn)或拒絕新狀態(tài)的過渡飘诗。)通知有名字,例如UITextFieldTextDidBeginEditingNotification, UITextViewTextDidEndEditingNotification, 和 UITextViewTextDidChangeNotification界逛。和textFieldDidEndEditing: 和 textViewDidEndEditing:一樣昆稿,觀察并處理UITextFieldTextDidEndEditingNotification 和 UITextViewTextDidEndEditingNotification通知是為了訪問相關(guān)的文本字段和文本視圖。更多關(guān)于通過這些類發(fā)送的通知的信息息拜,參見UITextField Class Reference 和 UITextView Class Reference 溉潭。
配置文本字段和文本視圖
就像所有由UIKit框架提供的視圖對(duì)象一樣,你通常需要在文本字段和文本視圖顯示之前配置它們少欺。你可以用編程方式配置它們喳瓣,也可以使用在Interface Builder中的屬性檢查器來配置它們。這兩種方式赞别,你都是在設(shè)置文本對(duì)象的屬性畏陕。
有一些屬性對(duì)于文本視圖和文本對(duì)象是常見的,但是也有一些屬性對(duì)于每個(gè)類型的對(duì)象都是特定的仿滔,包括以下幾個(gè):
- 文本特性——文本顏色惠毁、對(duì)齊方式、字體族崎页、字體鞠绰、以及字體尺寸。
- 鍵盤——鍵盤類型飒焦、返回鍵名字蜈膨、安全文本輸入、以及自動(dòng)啟用的返回鍵牺荠,所有這些都通過UITextInputTraits協(xié)議聲明翁巍。(注意,與文本視圖相關(guān)聯(lián)的自動(dòng)啟用會(huì)車鍵休雌,在點(diǎn)擊時(shí)灶壶,它的行為和回車鍵一樣。)更多信息挑辆,參見“為文本對(duì)象配置鍵盤”例朱。
- 文本字段特有——邊框孝情、背景圖片鱼蝉、禁用圖片、清除按鈕箫荡、以及展位文本魁亦。作為一個(gè)UIControl對(duì)象,文本字段也可以有高亮羔挡、選擇洁奈、啟用间唉、和其他屬性。
- 文本視圖特有——可編輯狀態(tài)利术、數(shù)據(jù)探測(cè)器(針對(duì)電話號(hào)碼和URL連接)呈野。因?yàn)槲谋疽晥D繼承自UIScrollView,你可以通過設(shè)置合適的屬性個(gè)來管理滾動(dòng)視圖的行為印叁。
跟蹤多個(gè)文本字段或文本視圖
所有的UITextFieldDelegate或UITextViewDelegate協(xié)議的方法被冒,都有一個(gè)屬性來識(shí)別文本字段或文本視圖第一響應(yīng)者狀態(tài)的改變、值的改變轮蜕、或者其他委托信息原因的改變昨悼。如果只有一個(gè)文本對(duì)象在當(dāng)前的視圖中顯示,該文本對(duì)象通過上面的屬性進(jìn)行驗(yàn)證跃洛。但是率触,如果當(dāng)前視圖上面有多個(gè)文本字段或者文本視圖,委托必須找到某種方式來指示該文本對(duì)象就是委托信息的對(duì)象汇竭。
你可以使用以下兩種方法來確定:outlet或tag葱蝗。對(duì)于outlet方法,聲明一個(gè)outlet實(shí)例變量 (使用IBOutlet關(guān)鍵字)细燎,并建立一個(gè)outlet連接垒玲。在你的委托方法中,使用指針對(duì)照找颓,測(cè)試傳入的文本對(duì)象是否與outlet指示的對(duì)象相同合愈。例如,假設(shè)你聲明并連接了一個(gè)名為SSN的outlet击狮。你的代碼應(yīng)該和代碼清單3-1類似佛析。
代碼清單 3-1 使用outlet識(shí)別傳入的文本對(duì)象
- (BOOL)textFieldShouldEndEditing:(UITextField *)textField {
if (textField == SSN) {
// .....
return NO;
}
return YES;
}
當(dāng)你需要將字符串值寫入到文本對(duì)象中,而不僅僅是獲取它們彪蓬,那么為在視圖中的這些文本對(duì)象定義outlet連接特別有用寸莫,甚至是必要的。
而對(duì)于tag方式档冬,聲明一組枚舉常量膘茎,每個(gè)tag對(duì)應(yīng)一個(gè)常量。
enum {
NameFieldTag = 0,
EmailFieldTag,
DOBFieldTag,
SSNFieldTag
};
然后通過編程方式或者Interface Builder方式把整型值分配給文本對(duì)象的tag屬性酷誓。(tag屬性在UIView中聲明了披坏。)在委托方法中,你可以使用seitch語句來評(píng)估傳入的文本對(duì)象的tag值盐数,從而繼續(xù)(如代碼清單3-2所示)棒拂。
文本清單 3-2 使用tag識(shí)別傳入的文本對(duì)象
- (void)textFieldDidEndEditing:(UITextField *)textField {
switch (textField.tag) {
case NameFieldTag:
// do something with this text field
break;
case EmailFieldTag:
// do something with this text field
break;
// remainder of switch statement....
}
}
獲取輸入的文本并設(shè)置文本
在用戶在文本字段或文本視圖中輸入或者編輯文本且編輯會(huì)話結(jié)束之后,委托將獲得文本,并把它存儲(chǔ)在應(yīng)用的數(shù)據(jù)模型中帚屉。對(duì)于訪問輸入文本的最好的委托方法是textFieldDidEndEditing: (文本字段) 和 textViewDidEndEditing: (文本視圖).
代碼清單 3-3 演示了如何獲取用戶在文本字段中(使用tag值來在視圖中區(qū)別多個(gè)文本字段)輸入的文本谜诫。UITextField或者UITextView的text屬性通過文本對(duì)象持后當(dāng)前顯示的字符串。委托從該屬性中獲取字符串攻旦,并把它存儲(chǔ)在一個(gè)字典對(duì)象中喻旷。如果該文本字段換沒有字符串值(就是該字段持有一個(gè)空字符串),該委托就簡單的返回牢屋。
代碼清單 3-3 在文本字段中獲取輸入的文本
- (void)textFieldDidEndEditing:(UITextField *)textField {
if ([textField.text isEqualToString:@""])
return;
switch (textField.tag) {
case NameFieldTag:
[thePerson setObject:textField.text forKey:MyAppPersonNameKey];
break;
case EmailFieldTag:
[thePerson setObject:textField.text forKey:MyAppPersonEmailKey];
break;
case SSNFieldTag:
[thePerson setObject:textField.text forKey:MyAppPersonSSNKey];
break;
default:
break;
}
}
代碼清單 3-4 顯示了textViewDidEndEditing: 方法的實(shí)現(xiàn)掰邢,它從文本視圖中獲取顯示的字符串,并把它存儲(chǔ)在字典中伟阔。這個(gè)方法不要求文本視圖注冊(cè)為第一響應(yīng)者辣之。(resignFirstResponder方法在動(dòng)作方法被調(diào)用之前被調(diào)用,該動(dòng)作方法在用戶在視圖的用戶界面上點(diǎn)擊完成按鈕的時(shí)候被調(diào)用皱炉。)
代碼清單 3-4 在文本視圖中獲取輸入的文本
- (void)textViewDidEndEditing:(UITextView *)textView {
NSString *theText = textView.text;
if (![theText isEqualToString:@""]) {
[thePerson setObject:theText forKey:MyAppPersonNotesKey];
}
doneButton.enabled = NO;
}
如果你需要把字符串值寫入文本對(duì)象(通常在從app的數(shù)據(jù)模型檢索它們之后)怀估,只需要簡單的把字符串分配給文本對(duì)象的text屬性即可。例如:
NSString *storedValue = [thePerson objectForKey:MyAppPersonEmailKey];
emailField.text = storedValue;
為此,給想要寫入字符串的文本字段換或者文本視圖(在這個(gè)例子中時(shí)emailField)定義outlet是有用的。
在文本字段使用格式化器
格式化器對(duì)象自動(dòng)解析在特定格式中的字符串帅掘,并且將該字符串轉(zhuǎn)換成代表數(shù)字、日期康铭、或其他值的對(duì)象;它們還可以反操作赌髓,把NSData从藤、NSNumber、以及類似的對(duì)象轉(zhuǎn)換為代表這些對(duì)象值的格式化字符串锁蠕。Foundation框架提供抽象基礎(chǔ)類NSFormatter和兩個(gè)具體子類NSDateFormatter和NSNumberFormatter夷野。始終這些類,用戶可以在文本字段輸入類似下面的值:
11/15/2010
-1,348.09
然后app可以使用formatter對(duì)象將字符串分別轉(zhuǎn)換為NSData對(duì)象和NSNumber對(duì)象荣倾。
下面的代碼清單悯搔,使用了日期格式化器對(duì)象來說明格式化器的使用。(當(dāng)然舌仍,你可以使用UIDatePicker對(duì)象來代替文本字段輸入日期妒貌,而附加日期格式化器的文本字段是另一個(gè)選項(xiàng)。)代碼清單3-5中的代碼铸豁,創(chuàng)建了一個(gè)NSDateFormatter對(duì)象灌曙,并且給它分配了一個(gè)實(shí)例變量。它配置這個(gè)日期格式化器來使用日期的“短樣式”推姻,但是在某種程度上可以響應(yīng)日歷平匈、區(qū)域、以及時(shí)區(qū)的改變藏古。它還把今天的日期分配給給定的格式作為占位字符串增炭,以便用戶在輸入日期的時(shí)候有一個(gè)可以遵照的模型。
代碼清單 3-5 配置日期格式化器
- (void)viewDidLoad {
[super viewDidLoad];
dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setGeneratesCalendarDates:YES];
[dateFormatter setLocale:[NSLocale currentLocale]];
[dateFormatter setCalendar:[NSCalendar autoupdatingCurrentCalendar]];
[dateFormatter setTimeZone:[NSTimeZone defaultTimeZone]];
[dateFormatter setDateStyle:NSDateFormatterShortStyle]; // example: 4/13/10
DOB.placeholder = [NSString stringWithFormat:@"Example: %@", [dateFormatter stringFromDate:[NSDate date]]];
// code continues....
}
在你配置了日期格式化器之后拧晕,該委托可以調(diào)用格式化器的dateFromString:方法隙姿,來把輸入的日期字符串轉(zhuǎn)換為NSData對(duì)象。代碼清單3-6顯示了此過程厂捞。
代碼清單3-6 使用NSDateFormatter對(duì)象输玷,把日期字符串轉(zhuǎn)化為數(shù)據(jù)對(duì)象
- (void)textFieldDidEndEditing:(UITextField *)textField {
[textField resignFirstResponder];
if ([textField.text isEqualToString:@""])
return;
switch (textField.tag) {
case DOBField:
NSDate *theDate = [dateFormatter dateFromString:textField.text];;
if (theDate)
[inputData setObject:theDate forKey:MyAppPersonDOBKey];
break;
// more switch case code here...
default:
break;
}
}
使用了格式化器并不能保證輸入的字符串必定包含了有效值(例如,用戶可以輸入13作為格里高利日歷的月份值)靡馁。為了確保用戶輸入正確的值欲鹏,委托必須驗(yàn)證字符串,這部分在驗(yàn)證輸入文本中已經(jīng)解釋了臭墨。因?yàn)轵?yàn)證經(jīng)常要求已知的格式和有效值的范圍赔嚎,如果你想代碼清單3-5那樣配置日期格式化器,以便它對(duì)于不同的日歷和區(qū)域敏感胧弛,則無法肯定的知道該格式尤误。想要指定一個(gè)已知的日期格式,通過調(diào)用setDateFormat:來配置日期格式化器结缚,給它傳遞一個(gè)通過Unicode標(biāo)準(zhǔn)定義的格式模型损晤。
你還可以將上面演示的過程反過來:把數(shù)據(jù)對(duì)象轉(zhuǎn)換成通過調(diào)用NSDateFormatter的方法stringFromDate:生成的字符串,然后把該字符串分配給文本字段红竭、文本視圖或者標(biāo)簽的text屬性尤勋。
更多關(guān)于NSDateFormatter和NSNumberFormatter的信息,參見Data Formatting Guide茵宪。
驗(yàn)證輸入的文本
App有時(shí)候不能接收在文本字段和文本視圖中輸入的沒有驗(yàn)證的字符串斥黑。或許該字符串必須是某種格式眉厨,也或者該值必須在特定范圍之內(nèi)锌奴。驗(yàn)證輸入字符串最好的委托方法,對(duì)于文本字段來說是textFieldShouldEndEditing:憾股,對(duì)于文本視圖來說是textViewShouldEndEditing:鹿蜀。這些方法在文本字段或文本視圖注冊(cè)為第一響應(yīng)者之前調(diào)用。返回NO來防止這種情況的發(fā)生服球,因此文本對(duì)象依然是編輯的重點(diǎn)茴恰。如果輸入的字符串是無效的,你還應(yīng)該顯示警告來提醒用戶這個(gè)錯(cuò)誤斩熊。
代碼清單3-7使用正則表達(dá)式來驗(yàn)證在“社會(huì)保障號(hào)碼”字段中輸入的字符串是否符合特定的格式往枣。
代碼清單 3-7 實(shí)用正則表達(dá)式驗(yàn)證文本字段的字符串格式
- (BOOL)textFieldShouldEndEditing:(UITextField *)textField {
if (textField == SSN) { // SSN is an outlet
NSString *regEx = @"[0-9]{3}-[0-9]{2}-[0-9]{4}";
NSRange r = [textField.text rangeOfString:regEx options:NSRegularExpressionSearch];
if (r.location == NSNotFound) {
UIAlertView *av = [[[UIAlertView alloc] initWithTitle:@"Entry Error"
message:@"Enter social security number in 'NNN-NN-NNNN' format"
delegate:self cancelButtonTitle:@"OK" otherButtonTitles:nil] autorelease];
[av show];
return NO;
}
}
return YES;
}
在代碼清單3-8中,實(shí)現(xiàn)了textViewShouldEndEditing:方法,強(qiáng)制限制了在文本視圖中輸入的文本的字符數(shù)分冈。
代碼清單 3-8 驗(yàn)證文本視圖允許的字符串長度
- (BOOL)textViewShouldEndEditing:(UITextView *)textView {
if (textView.text.length > 50) {
UIAlertView *av = [[[UIAlertView alloc] initWithTitle:@"Entry Error"
message:@"You must enter less than 50 characters." delegate:self cancelButtonTitle:@"OK"
otherButtonTitles:@"Clear", nil] autorelease];
[av show];
return NO;
}
return YES;
}
委托還可以通過實(shí)現(xiàn)textField:shouldChangeCharactersInRange:replacementString:方法圾另,來驗(yàn)證在文本字段中輸入的每個(gè)字符。代碼清單3-9中的代碼雕沉,驗(yàn)證了每個(gè)輸入的字符(字符串)代表一個(gè)數(shù)字集乔。(你可以通過給文本字段指定UIKeyboardTypeNumberPad鍵盤來實(shí)現(xiàn)相同的目標(biāo)。)
代碼清單 3-9 驗(yàn)證每個(gè)輸入的字符
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range
replacementString:(NSString *)string {
if ([string isEqualToString:@""]) return YES;
if (textField.tag == SalaryFieldTag) {
unichar c = [string characterAtIndex:0];
if ([[NSCharacterSet decimalDigitCharacterSet] characterIsMember:c]) {
return YES;
} else {
return NO;
}
}
return YES;
}
你可以實(shí)現(xiàn)textField:shouldChangeCharactersInRange:replacementString:方法坡椒,在用戶輸入文本的時(shí)候提供單詞的可能完整性和更正功能扰路。
在文本字段中使用覆蓋視圖
覆蓋視圖是一個(gè)插入到文本字段左側(cè)或右側(cè)的小視圖。作為控件倔叼,當(dāng)用戶點(diǎn)擊它們的時(shí)候汗唱,可以操作文本字段當(dāng)前的內(nèi)容。搜索和書簽是覆蓋視圖的兩種常見任務(wù)丈攒,但是其他也是可能的哩罪。覆蓋視圖可以使用文本字段中(部分)URL加載web瀏覽器:
想要實(shí)現(xiàn)覆蓋視圖,創(chuàng)建一個(gè)和文本字段高度尺寸匹配的視圖肥印,并給該視圖一個(gè)合適尺寸的圖片识椰。如果該視圖是一個(gè)按鈕或其他空間,請(qǐng)指定目標(biāo)對(duì)象深碱、動(dòng)作選擇器腹鹉、和觸發(fā)控件事件。通常來說敷硅,你希望在文本字段聚焦于編輯的時(shí)候出現(xiàn)覆蓋視圖功咒,所以把它分配給textFieldDidBeginEditing: 委托方法中的leftView 或者rightView屬性。在編輯會(huì)話期間(例如在用戶輸入文本之前绞蹦,或者用戶剛剛開始輸入文本之后)力奋,在覆蓋視圖出現(xiàn)的時(shí)候,你可以通過將UITextFieldViewMode常量分配給leftViewMode或rightViewMode屬性進(jìn)行控制幽七。代碼清單3-10演示了如何實(shí)現(xiàn)覆蓋視圖景殷。
代碼清單 3-10在文本字段中顯示覆蓋視圖。
- (void)textFieldDidBeginEditing:(UITextField *)textField {
if (textField.tag == NameField && self.overlayButton) {
textField.leftView = self.overlayButton;
textField.leftViewMode = UITextFieldViewModeAlways;
}
}
@dynamic overlayButton;
- (UIButton *)overlayButton {
if (!overlayButton) {
overlayButton = [[UIButton buttonWithType:UIButtonTypeCustom] retain];
UIImage *overlayImage = [UIImage imageNamed:@"bookmark.png"];
if (overlayImage) {
[overlayButton setImage:overlayImage forState:UIControlStateNormal];
[overlayButton addTarget:self action:@selector(bookmarkTapped:)
forControlEvents:UIControlEventTouchUpInside];
}
}
return overlayButton;
}
如果你想使用覆蓋視圖的空間澡屡,請(qǐng)確保實(shí)現(xiàn)了該動(dòng)作方法猿挚。
要想移除掉覆蓋視圖,只要在textFieldDidEndEditing:委托方法中驶鹉,將leftView或者rightView屬性簡單設(shè)置為nil即可绩蜻。參照代碼清單3-11。
代碼清單 3-11移除覆蓋視圖
- (void)textFieldDidEndEditing:(UITextField *)textField {
if (textField.tag == NameFieldTag) {
textField.leftView = nil;
}
// remainder of implementation....
}
跟蹤文本視圖中的所選部分
UITextViewDelegate中的方法textViewDidChangeSelection:讓你可以跟蹤用戶在文本視圖中所選擇部分的修改室埋。你可以實(shí)現(xiàn)方法來獲取選擇部分的子字符串办绝,并對(duì)它進(jìn)行操作伊约。代碼清單3-12 是一個(gè)怪誕的例子,它讓所選子字符串的字符都變成大寫孕蝉。
代碼清單 3-12 獲取選中的子字符串并更改它
- (void)textViewDidChangeSelection:(UITextView *)textView {
NSRange r = textView.selectedRange;
if (r.length == 0) {
return;
}
NSString *selText = [textView.text substringWithRange:r];
NSString *upString = [selText uppercaseString];
NSString *newString = [textView.text stringByReplacingCharactersInRange:r withString:upString];
textView.text = newString;
}