斯坦福大學(xué)iOS開(kāi)發(fā)公開(kāi)課總結(jié)(四 & 五) :屬性字符串Demo

2016.07.04日更新:

因?yàn)榈谒墓?jié)課和第五節(jié)課內(nèi)容相似,故合并在一起,為了使學(xué)習(xí)總結(jié)的序號(hào)和課程的一致性,更正了標(biāo)題。


本節(jié)課講解了iOS框架里幾個(gè)重要的知識(shí)點(diǎn):動(dòng)態(tài)綁定,控制器的生命周期,屬性字符串等。最后演示了一個(gè)Demo用來(lái)講解屬性字符串的幾個(gè)功能。

動(dòng)態(tài)綁定


在OC的編譯期,所有的指針都是id類型,只有在運(yùn)行時(shí),對(duì)象的類型才會(huì)被確定。

舉個(gè)?? :
在編譯期,NSString* 實(shí)際上與id相同,但是加上去的好處是讓編譯器知道你至少是意圖讓該指針指向一個(gè)字符串。所以如果嘗試發(fā)送非字符串消息給該指針,它會(huì)發(fā)出警告,但是不會(huì)提示錯(cuò)誤,仍可以通過(guò)編譯。但是如果在運(yùn)行時(shí)就會(huì)“露餡”,因?yàn)榇藭r(shí)如果向該對(duì)象發(fā)送非字符串消息時(shí),就會(huì)引起崩潰。

再舉個(gè)具體的??:

NSString *hellow = @"hello";
Ship *hellowShip = (Ship *)hello;
[helloShip shoot];

編譯器會(huì)認(rèn)為hellowShipship類型,因此向hellowShip發(fā)送shoot消息時(shí),在編譯器期是可以通過(guò)的。
但是,hellowShip實(shí)際上指向的是字符串,所以會(huì)導(dǎo)致在運(yùn)行時(shí)崩潰。

所以就引出了類型保護(hù)機(jī)制用來(lái)確定對(duì)象的類型:

類型保護(hù)機(jī)制


沒(méi)有添加類型保護(hù)機(jī)制:

PlayingCard *otherCard = [otherCards firstObject];
[otherCard play];

firstObject 方法返回的是id類型,這里需要保護(hù)機(jī)制確保取出的對(duì)象是PlayingCard的實(shí)例,以防止向其發(fā)送消息時(shí)導(dǎo)致程序崩潰。

添加了類型保護(hù)機(jī)制:

PlayingCard *otherCard = [otherCards firstObject];

id card = [otherCards firstObjct];
if ([card isKindOfClass:[PlayingCard class]])
{
   PlayingCard *otherCard = (PlaytingCard *)card;
   [otherCard play];

}

我們可以看到card指針通過(guò)isKindOfClass:方法被確認(rèn)了是PlayingCard類的實(shí)例,那么如果我們給card實(shí)例發(fā)送其消息時(shí),就不會(huì)發(fā)生崩潰。反之,若card是其他類的實(shí)例,如果向其發(fā)送card類的消息就會(huì)非常危險(xiǎn)!

NSRange


NSRange是一個(gè)表示“范圍”的結(jié)構(gòu)體,包括起點(diǎn)和長(zhǎng)度,主要用于字符串。

常用方法:

字符串所有的字符:

NSString *title = @"好好學(xué)習(xí)天天向上";
NSMakeRange(0, [title length])

判斷某個(gè)字符串里包含某個(gè)字符:

NSString *greeting = @"hellow world";
Nsstring *hi = @"hi";
NSRange r = [greeting rangeOfString:hi];
if(r.location != NSNotFound)
{
    NSLog(@"Found");
}

控制器生命周期


在控制器(ViewController)的生命周期里,處于某個(gè)特定的時(shí)間點(diǎn)會(huì)執(zhí)行某個(gè)特定的方法。通過(guò)在這些方法里之行某些特定的任務(wù),可以正確地實(shí)現(xiàn)其應(yīng)實(shí)現(xiàn)的功能。

viewDidLoad

控制器的viewDidLoad方法在控制器的view為nil的時(shí)候被調(diào)用,在控制器的生命周期中只調(diào)用一次。


- (voidviewDidLoad
{
   [super viewDidLoad];    
   
   //可執(zhí)行:
   //1. 控制器的初始化數(shù)據(jù)
   //2. 網(wǎng)絡(luò)請(qǐng)求
   
   
   //不可執(zhí)行:
   //1. 視圖形狀的初始化信息
}

viewWillAppear:

控制器的viewWillAppear:在UIViewController對(duì)象的視圖即將加入窗口時(shí)調(diào)用。只要該控制器的view即將要出現(xiàn),都會(huì)調(diào)用,在控制器的生命周期中可以調(diào)用多次。
而且,如果該方法被調(diào)用,就說(shuō)明視圖一定會(huì)出現(xiàn)在屏幕上。

- (void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];
    
    //可執(zhí)行:
    //1. 更新view離開(kāi)界面后可能會(huì)改變的數(shù)據(jù)。
    //2. view的幾何變化。
        
}

viewWillDisappear:

控制器的viewWillDisappear:在UIViewController的view即將不顯示的時(shí)候調(diào)用,在控制器的生命周期中可以調(diào)用多次。

- (void)viewWillDisappear:(BOOL)animated
{
    [super viewWillDisappear:animated];
    
    //可執(zhí)行:
    //1. 記錄滾動(dòng)視圖的偏移量(因?yàn)橐涀L動(dòng)位置,便于下次查看)
    //2. 存儲(chǔ)數(shù)據(jù),便于再次顯示該控制器時(shí)使用。
}

屬性字符串Demo


設(shè)計(jì)需求

  • 布局為TextView下方有四個(gè)顏色按鈕,再下方有添加輪廓按鈕和去除輪廓按鈕。
  • 選中TextView的文本后,點(diǎn)擊色彩按鈕,選中的文本的顏色變成點(diǎn)擊的色彩按鈕的背景色。
  • 選中TextView的文本后,點(diǎn)擊添加輪廓,選中的文本增加了輪廓,再點(diǎn)擊色彩按鈕,輪廓變成了相應(yīng)的顏色。
  • 文本有輪廓的狀態(tài)下,點(diǎn)擊去除輪廓按鈕,輪廓消失。
  • 在設(shè)置選項(xiàng)來(lái)改變系統(tǒng)字體,再回到本Demo界面,字體會(huì)做相應(yīng)改變。

效果圖

屬性字符串效果圖

知識(shí)點(diǎn)詳解

屬性字符串的設(shè)置

屬性字符串分為不可變屬性字符串NSAttributedStringNSMutableAttributedString。

設(shè)置屬性字符串的一般步驟為:

  1. 初始化可變屬性字符串。
  2. 向其添加屬性字典和制定屬性字典被應(yīng)用的范圍。

舉個(gè)??:


//1. 由現(xiàn)有字符串初始化可變屬性字符串
NSMutableAttributedString *title = [[NSMutableAttributedString alloc] initWithString:self.outLineButton.currentTitle];

//2. 添加屬性字典和范圍
[title setAttributes:@{NSStrokeWidthAttributeName : @3,
                      NSStrokeColorAttributeName  : self.outLineButton.tintColor}
                                             range: NSMakeRange(0, [title length])];

//3. 將屬性字符串賦給按鈕的屬性字符串屬性
[self.outLineButton setAttributedTitle:title forState:UIControlStateNormal];

//設(shè)定選中的字都被設(shè)置為和點(diǎn)擊的按鈕一樣的背景顏色
[self.textView.textStorage  addAttribute:NSForegroundColorAttributeName value:sender.backgroundColor range:self.body.selectedRange];

關(guān)于按鈕的操作

//獲取按鈕的背景色
self.button.backgroundColor

//獲取按鈕當(dāng)前的標(biāo)題
self.button.currentTitle

//設(shè)定按鈕當(dāng)前的屬性字符串標(biāo)題
[self.button setAttributedTitle:title forState:UIControlStateNormal];

屬性字典里的key:

  • NSForegroundColorAttributeName:屬性字符串字符的顏色
  • NSStrokeColorAttributeName:屬性字符串字符輪廓的顏色
  • NSStrokeWidthAttributeName:屬性字符串字符輪廓的寬度

獲取TextView被選中的范圍

self.textView.selectedRange

通知機(jī)制

為了實(shí)現(xiàn)本Demo最后一個(gè)需求,我們需要監(jiān)聽(tīng)系統(tǒng)字體何時(shí)被改變了。所以需要注冊(cè)一個(gè)能收聽(tīng)“系統(tǒng)改變”廣播的頻道:

注冊(cè)通知:

 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(prefredFontsChaged:) name:UIContentSizeCategoryDidChangeNotification object:nil];

這樣一來(lái),當(dāng)系統(tǒng)字體發(fā)生變化時(shí),注冊(cè)該頻道的對(duì)象會(huì)收到通知并執(zhí)行自定義的方法。
當(dāng)改變系統(tǒng)字體的大小后,該類會(huì)收到通知,并調(diào)用prefredFontsChaged:方法,此時(shí)Demo上的字體也要做相應(yīng)的改變:

- (void)prefredFontsChaged: (NSNotification *)notification
{
    //收到通知后,調(diào)用本地自定義的方法
    [self userPreferredFonts];
}

- (void)userPreferredFonts
{
    //使用被改變后的系統(tǒng)字體
    self.body.font = [UIFont preferredFontForTextStyle:UIFontTextStyleBody];
    self.headLine.font = [UIFont preferredFontForTextStyle:UIFontTextStyleHeadline];
    
}

這里,顯然又是一個(gè)MVC的流程:系統(tǒng)字體(模型)被改變了,通過(guò)廣播(通知)的機(jī)制來(lái)告訴控制器,然后控制器再調(diào)用更改View的方法。還記得在第一篇(詳情請(qǐng)見(jiàn):斯坦福大學(xué)iOS開(kāi)發(fā)公開(kāi)課總結(jié)(一) :iOS的MVC框架)里強(qiáng)調(diào)的,從模型到控制器的通信是通過(guò)廣播或KVO機(jī)制完成的么?

最后的話


如果哪位小伙伴想拿到此Demo的代碼請(qǐng)不要客氣,在評(píng)論里留言即可。
而且十分歡迎給筆者的代碼和文筆拋出寶貴的意見(jiàn)和建議~

本文為筆者原創(chuàng),如需轉(zhuǎn)載,請(qǐng)事先與筆者交涉~

2016.7.12日更新:


筆者已經(jīng)把目前為止整理的所有Demo(第二課到第十課)放入到了我的GitHub倉(cāng)庫(kù)里。分為英文注釋版和中文注釋版(英文注釋要少一點(diǎn),嘿嘿)想要的小伙伴可以果斷下載~ 如果有不知道怎么下載的小伙伴請(qǐng)聯(lián)系我~

本文已在版權(quán)印備案,如需轉(zhuǎn)載請(qǐng)?jiān)L問(wèn)版權(quán)印。48422928

獲取授權(quán)

-------------------------------- 2018年7月17日更新 --------------------------------

注意注意?。?!

筆者在近期開(kāi)通了個(gè)人公眾號(hào),主要分享編程,讀書(shū)筆記,思考類的文章。

  • 編程類文章:包括筆者以前發(fā)布的精選技術(shù)文章,以及后續(xù)發(fā)布的技術(shù)文章(以原創(chuàng)為主),并且逐漸脫離 iOS 的內(nèi)容,將側(cè)重點(diǎn)會(huì)轉(zhuǎn)移到提高編程能力的方向上。
  • 讀書(shū)筆記類文章:分享編程類,思考類,心理類,職場(chǎng)類書(shū)籍的讀書(shū)筆記。
  • 思考類文章:分享筆者平時(shí)在技術(shù)上生活上的思考。

因?yàn)楣娞?hào)每天發(fā)布的消息數(shù)有限制,所以到目前為止還沒(méi)有將所有過(guò)去的精選文章都發(fā)布在公眾號(hào)上,后續(xù)會(huì)逐步發(fā)布的。

而且因?yàn)楦鞔蟛┛推脚_(tái)的各種限制,后面還會(huì)在公眾號(hào)上發(fā)布一些短小精干,以小見(jiàn)大的干貨文章哦~

掃下方的公眾號(hào)二維碼并點(diǎn)擊關(guān)注,期待與您的共同成長(zhǎng)~

公眾號(hào):程序員維他命
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 178,836評(píng)論 25 709
  • 發(fā)現(xiàn) 關(guān)注 消息 iOS 第三方庫(kù)、插件、知名博客總結(jié) 作者大灰狼的小綿羊哥哥關(guān)注 2017.06.26 09:4...
    肇東周閱讀 15,117評(píng)論 4 61
  • 《幸福的種子》是我接觸的第一本繪本理論方向的書(shū)籍,作者松居直被譽(yù)為日本圖畫(huà)書(shū)之父,透過(guò)書(shū)中的文字與之對(duì)話,他如同一...
    北燕楠飛閱讀 538評(píng)論 0 7
  • 也許每個(gè)人都會(huì)聽(tīng)到過(guò)這樣的一種聲音,在夜深人靜的時(shí)候,樓上的一種奇特的聲音。 “嗒…嗒…嗒嗒嗒……”仿佛是玻璃球敲...
    山月有蹤閱讀 972評(píng)論 0 1
  • 聊天,是最基本的生活方式。通過(guò)友好的交談,可以增進(jìn)彼此的友誼,獲取新鮮的知識(shí),想要達(dá)到這個(gè)結(jié)果,就需要技巧,而不是...
    蝸牛up666閱讀 216評(píng)論 0 0

友情鏈接更多精彩內(nèi)容