標(biāo)題顯得很屌絲,搞那么長、長就長一點(diǎn)吧,這樣可能方便搜索。
一、先看一張圖

是的、就這三個(gè)分類:NSString+Regex,UITextField+HG,UITextView+HG。接下來就對他們做一個(gè)簡單的介紹。
二、如何獲取
在之前、已經(jīng)放到 pod 上。所以獲取方式有兩種:
1、直接到這里Categorys去查看。
2、通過 pod 方式拉?。?/p>
pod 'HGCategorys'
溫馨提示:一般 Podfile 應(yīng)該如何去創(chuàng)建?很多同行是這樣的命令:vim Podfile,其實(shí)最專業(yè)&方便的創(chuàng)建姿勢是這樣的:pod init 。
看了代碼之后會發(fā)現(xiàn)實(shí)現(xiàn)是很簡單的,不僅代碼簡單、功能也很簡單。存在、就是真理。再簡單、也一起看一看有何用途吧。
三、有何功能
1、NSString+Regex
先看分類名 Regex,正則表達(dá)式的意思。那么這部分的功能就很明確了,主要就是一個(gè)字符串的匹配。在開發(fā)的過程中對 正則表達(dá)式 的使用幾乎是不難的,但是如何將不同的功能整合在一起,這恐怕是一個(gè)問題。接下來看一看這里面到底是如何實(shí)現(xiàn)的(只看.h 文件中的內(nèi)容)。
1.1 枚舉定義
具體定義如下:
// 基本匹配 : 數(shù)字, 漢字, 字符, 空格, 下劃線, 點(diǎn), @
typedef NS_OPTIONS(NSUInteger, HGRegexType) {
HGRegexTypeNone = 0 << 0, // 未知
HGRegexTypeDigital = 1 << 0, // 數(shù)字
HGRegexTypeChinese = 1 << 1, // 漢字
HGRegexTypeCharacter = 1 << 2, // 字符
HGRegexTypeSpace = 1 << 3, // 空格
HGRegexTypeUnderline = 1 << 4, // 下劃線
HGRegexTypeDot = 1 << 5, // 點(diǎn)
HGRegexTypeAT = 1 << 6, // @
};
關(guān)于這個(gè)枚舉的定義的一大亮點(diǎn)就是 NS_OPTIONS,千萬不要看成 NS_ENUM,這兩種枚舉在用法上是有很大區(qū)別的。相比較而言 NS_OPTIONS 的功能比 NS_ENUM 還要強(qiáng)大。這里并不說我現(xiàn)在使用了 NS_OPTIONS 就吹噓它強(qiáng)大,而顯得自己有多牛逼。不是這樣的、而是想說,對于OC 中的枚舉一定要弄清楚這兩種的不同。在適當(dāng)?shù)臅r(shí)機(jī)使用適當(dāng)?shù)膶?shí)現(xiàn)方式,才能讓自己的代碼更加合理、更加牛氣。
其實(shí)蘋果給我們提供了很多這樣的枚舉,比如 UIViewAutoresizing、NSKeyValueObservingOptions 等等。
看到這里,應(yīng)該能猜測到 HGRegexType 的用途是什么了。我不說、你不說,心里知道就可以了。[偷笑 5 秒鐘、思考一小時(shí)]
1.2 提供的方法
在上代碼之前,先自我批評一下:所有的方法注釋,沒有對參數(shù)做介紹。這是在寫代碼過程中的大忌,在 .m 文件中可以不用、但是在 .h 文件中不做注釋,這肯定是不對的。由于代碼是3個(gè)月前上傳的,也不想去更新了。
直接看代碼:
/**
* 通過 pattern 進(jìn)行匹配
*/
- (BOOL)hg_regexMatchWithPattern:(NSString*)pattern;
/**
* 基本匹配: 是否支持空字符串返回為YES的情況
*/
- (BOOL)hg_regexMatchWithType:(HGRegexType)rType returnWhenEmpty:(BOOL)empty;
看過代碼的你應(yīng)該知道,實(shí)際提供的方法不止以上的兩個(gè)。但是沒有關(guān)系,只要明白了這兩個(gè)方法,其它方法看到就秒懂了。接下來細(xì)說一下這兩個(gè)方法。
/**
* 通過 pattern 進(jìn)行匹配
*/
- (BOOL)hg_regexMatchWithPattern:(NSString*)pattern;
當(dāng)你看到這個(gè)方法,根據(jù)你多年的開發(fā)經(jīng)驗(yàn),再加上我那么屌絲的注釋,你可能會這樣的去用:
// 匹配的條件
NSString* pattern = @".";
// 即將匹配的字符串
NSString* strTEXT = @"CoderHG.";
// 匹配結(jié)果
BOOL result = [hg_regexMatchWithPattern:pattern];
// 打印
if (result) {
NSLog(@"有點(diǎn)");
} else {
NSLog(@"沒點(diǎn)");
}
毫無保留的認(rèn)為 strTEXT 中有一個(gè)點(diǎn)(.),所以結(jié)果 result 的值是 YES,打印的是 有點(diǎn)。其實(shí)不是這樣,這里的結(jié)果是 NO。我的這個(gè)方法的意思是要 完全匹配 才算 YES,因?yàn)槲抑霸O(shè)計(jì)這個(gè)匹配功能的初衷是:一個(gè)字符串中只能只包含 pattern 中的字符,如果多了,就算失敗。
所以、以上如果想要讓 strTEXT 完全匹配成功,只能是將 pattern 改成這樣 ^[a-zA-Z.]+$,意思是 strTEXT 中只能出現(xiàn)字符與點(diǎn)(.)的情況下才能成功,多了,都是失敗。顯然 strTEXT 中除了點(diǎn)(.)還有其它,所以為 NO。
這樣的功能,一般用于什么樣的地方呢?比較常用的地方就是,密碼驗(yàn)證。往往會有這樣的要求:有且只能用字符、數(shù)字與下劃線。所以就可以弄弄成這樣的:
// 匹配的條件
NSString* pattern = @"^[\\da-zA-Z_]+$";
// 即將匹配的字符串
NSString* strTEXT = @"CoderHG123";
// 匹配結(jié)果
BOOL result = [strTEXT hg_regexMatchWithPattern:pattern];
// 打印
if (result) {
NSLog(@"%@ 中只包含數(shù)字,字符與下劃線", strTEXT);
} else {
NSLog(@"%@ 中除了包含數(shù)字,字符與下劃線,還有其它字符", strTEXT);
}
如果 strTEXT 中還包含了 數(shù)字,字符與下劃線 之外的字符,那么就返回 NO。
那么問題又來了,每次都要去寫 pattern 這樣的正則表達(dá)式,還麻煩啊。是的,的確是很麻煩的。接下來看另外一個(gè)方法。
/**
* 基本匹配: 是否支持空字符串返回為YES的情況
*/
- (BOOL)hg_regexMatchWithType:(HGRegexType)rType returnWhenEmpty:(BOOL)empty;
這個(gè)方法中,終于使用上那個(gè)枚舉(HGRegexType)了,看了上的所有解釋,應(yīng)該都知道這個(gè) rType 如何傳值了。但是后面的 empty 是怎么回事么?主要是為了處理給空字符串(@"")而準(zhǔn)備的。如果是空字符串(@"")的話,是算匹配成功還是匹配失敗呢。主要還是要看心情,不對、主要還是要看需求。 empty 傳什么,在如果是空字符串(@"")的時(shí)候就返回什么。
那么我們就可以來用一下了,如果一個(gè)需求是這樣的:一個(gè)字符串只能包含字母、數(shù)字與下劃線,并且如果當(dāng)前字符串為空(@"")的時(shí)候,返回為 YES。那么就可以這樣弄了:
// 即將匹配的字符串
NSString* strTEXT = @"CoderHG123";
// 匹配的條件 數(shù)字 | 字母 | 下劃線
HGRegexType rType = HGRegexTypeDigital | HGRegexTypeCharacter | HGRegexTypeUnderline;
// 匹配結(jié)果
BOOL result = [strTEXT hg_regexMatchWithType:rType returnWhenEmpty:YES];
// 打印
if (result) {
NSLog(@"%@ 中只包含數(shù)字,字符與下劃線", strTEXT);
} else {
NSLog(@"%@ 中除了包含數(shù)字,字符與下劃線,還有其它字符", strTEXT);
}
這樣看起來,就清晰了很多。到現(xiàn)在為止,NSString+Regex 部分就介紹結(jié)束了,希望能對你有所幫助。
欲知更多精彩,請看下面分解。
2、UITextField+HG
這部分不做介紹,功能與 UITextView+HG 類似,直接看 UITextView+HG 即可。
3、UITextView+HG
其實(shí)對于文本框的輸入,是有很多的話要說的,但是接下來要介紹的僅僅是其中的冰山一角。當(dāng)遇到輸入文本時(shí),還需要有文字限制的時(shí)候,應(yīng)該如何去處理。比如現(xiàn)在的微信(現(xiàn)在的版本號是6.6.5)的個(gè)性簽名只能輸入30個(gè)字符,多一個(gè)就不行。像我的個(gè)性簽名是這樣的:

一看我的個(gè)性簽名,我感覺確實(shí)很有個(gè)性的。微信只讓最多輸入30個(gè)字符,我就不多也不少的弄30個(gè)。其中 升值 的意思是: 努力提升自己的價(jià)值。
但是如果我現(xiàn)在想將 感謝自己! 換成感謝所有人,那么是修改不成功的,因?yàn)槲⑿鸥揪洼斎氩贿M(jìn)去了。這說明什么呢??[郁悶3秒鐘、思考幾十年]

現(xiàn)在總結(jié)一下微信個(gè)性簽名的文字限制的一個(gè)特點(diǎn):在輸入還處于高亮的時(shí)候,就已經(jīng)開始計(jì)算字符。導(dǎo)致在最后無法輸入想要輸入的結(jié)果。
如果說一定要感謝所有人, 應(yīng)該這么處理呢?目的就是要打破上面的那一個(gè)特點(diǎn):在輸入的過程中,高亮的部分不參與字符計(jì)算。于是 UITextView+HG 就誕生了。
關(guān)于這個(gè) 分類,實(shí)現(xiàn)是很簡單的。如果要完全的實(shí)現(xiàn) 在輸入的過程中,高亮的部分不參與字符計(jì)算。還需要其它的處理?,F(xiàn)在先來看一下這個(gè)分類都做了什么處理。主要就一個(gè)屬性與一個(gè)方法:
/** 是否高亮 */
@property (nonatomic, readonly) BOOL hg_isHighLighted;
/**
輸入無效,將已經(jīng)數(shù)據(jù)的打回原形
@param curContent 希望當(dāng)前的顯示內(nèi)容
*/
- (void)hg_invalidTextFieldCurContent:(NSString*)curContent;
hg_isHighLighted 諸葛屬性主要是用來判斷當(dāng)前的輸入框是否在處于高亮的狀態(tài)。
重點(diǎn)是下面的方法:
注釋中的 輸入無效,將已經(jīng)數(shù)據(jù)的打回原形,當(dāng)輸入超出限制的時(shí)候,將高亮的部分去掉去掉,回到高亮之前的狀態(tài)。這個(gè)方法中不僅處理了在文本的最后輸入的情況,主要是處理了在文本的中間部分輸入的情況下。光標(biāo)不會跑到最后,而是在高亮的上一個(gè)位置。聽起來很高大上,同時(shí)也很模糊??梢缘?HGCategorysDemo 目錄中找到具體的項(xiàng)目代碼,這個(gè)代碼最好是:pod update 一下。
具體的功能是在 SetupSignatureCell 中實(shí)現(xiàn)的,發(fā)現(xiàn)這里面的代碼不少,主要是一些代理與數(shù)字的控制。與之相關(guān)的代碼,在這里:
#pragma mark -
#pragma mark - UITextViewDelegate
- (void)textViewDidChange:(UITextView *)textView {
// 必須要在這里弄.
self.placeholderLabel.hidden = (textView.text.length > 0);;
// 如果在變化中是高亮部分在變,就不要計(jì)算字符了
if (textView.hg_isHighLighted) {
return ;
}
// 主要是處理當(dāng)輸入超出限制時(shí)的優(yōu)化
if (textView.text.length > self.maxCount) {
[textView hg_invalidTextFieldCurContent:_signatureTEXT];
}
// 代理
if (self.delegate && [self.delegate respondsToSelector:@selector(setupSignatureCell:didChangedValue:)]) {
[self.delegate setupSignatureCell:self didChangedValue:textView.text];
}
// 保留
// 不能這么調(diào)用
// self.signatureTEXT = textView.text;
// 正確的姿勢是這樣的
_signatureTEXT = textView.text;
_countLabel.text = [NSString stringWithFormat:@"%zd/%zd", self.signatureTEXT.length, (self.maxCount - self.signatureTEXT.length)];
}
是的,沒有錯(cuò),僅僅是在一個(gè)地方用到。其中,值得注意的是 signatureTEXT 這個(gè)屬性是必不可少的。如果沒有,那么光標(biāo)的問題很難處理。現(xiàn)在感興趣的話,就可以慢慢的看這個(gè)SetupSignatureCell 中實(shí)現(xiàn)。到此為止,UITextView+HG 的介紹以及一個(gè)個(gè)性簽名的實(shí)現(xiàn)基本上結(jié)束了。
4、說點(diǎn)題外話
對于 UITextField ,大家盡量不要去使用通知來控制各種狀態(tài),最好是使用代理與事件。別忘了UITextField是繼承于 UIControl 的。在 UITextView 的delegate 中有 textViewDidChange: 這樣的代理方法,但是在 UITextField 中卻是沒有的,我們可以通過UIControlEventEditingChanged來添加事件。如:
[textField addTarget:self action:@selector(textFieldDidChange:) forControlEvents:UIControlEventEditingChanged];
// 文本變化
- (void)textFieldDidChange:(UITextField *)textField
{
// TODO:
}
四、說在最后的話
本來打算上午就弄完的,沒想到搞到了現(xiàn)在。感謝閱讀的你、也感謝自己!
以上的功能,不值一提,都是冰山一角。不積跬步無以至千里,我們一步一步的來。
如果由于剛剛時(shí)間倉促,忘記了下拉代碼,那么可以直接點(diǎn)擊這里點(diǎn)擊這里點(diǎn)擊這里。關(guān)于個(gè)性簽名的代碼,記得到 HGCategorysDemo 目錄的查看。
要是有什么不對的、或者需要補(bǔ)充的,感謝評論討論!
我的更多文章,可以直接看這里NewStart NewStart NewStart
謝謝大家!
你說得很對,但是沒有意義。-- 來自 《職來職往》