斯坦福大學iOS開發公開課總結(四 & 五) :屬性字符串Demo

2016.07.04日更新:

因為第四節課和第五節課內容相似,故合并在一起,為了使學習總結的序號和課程的一致性,更正了標題。


本節課講解了iOS框架里幾個重要的知識點:動態綁定,控制器的生命周期,屬性字符串等。最后演示了一個Demo用來講解屬性字符串的幾個功能。

動態綁定


在OC的編譯期,所有的指針都是id類型,只有在運行時,對象的類型才會被確定。

舉個?? :
在編譯期,NSString* 實際上與id相同,但是加上去的好處是讓編譯器知道你至少是意圖讓該指針指向一個字符串。所以如果嘗試發送非字符串消息給該指針,它會發出警告,但是不會提示錯誤,仍可以通過編譯。但是如果在運行時就會“露餡”,因為此時如果向該對象發送非字符串消息時,就會引起崩潰。

再舉個具體的??:

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

編譯器會認為hellowShipship類型,因此向hellowShip發送shoot消息時,在編譯器期是可以通過的。
但是,hellowShip實際上指向的是字符串,所以會導致在運行時崩潰。

所以就引出了類型保護機制用來確定對象的類型:

類型保護機制


沒有添加類型保護機制:

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

firstObject 方法返回的是id類型,這里需要保護機制確保取出的對象是PlayingCard的實例,以防止向其發送消息時導致程序崩潰。

添加了類型保護機制:

PlayingCard *otherCard = [otherCards firstObject];

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

}

我們可以看到card指針通過isKindOfClass:方法被確認了是PlayingCard類的實例,那么如果我們給card實例發送其消息時,就不會發生崩潰。反之,若card是其他類的實例,如果向其發送card類的消息就會非常危險!

NSRange


NSRange是一個表示“范圍”的結構體,包括起點和長度,主要用于字符串。

常用方法:

字符串所有的字符:

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

判斷某個字符串里包含某個字符:

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

控制器生命周期


在控制器(ViewController)的生命周期里,處于某個特定的時間點會執行某個特定的方法。通過在這些方法里之行某些特定的任務,可以正確地實現其應實現的功能。

viewDidLoad

控制器的viewDidLoad方法在控制器的view為nil的時候被調用,在控制器的生命周期中只調用一次。


- (voidviewDidLoad
{
   [super viewDidLoad];    
   
   //可執行:
   //1. 控制器的初始化數據
   //2. 網絡請求
   
   
   //不可執行:
   //1. 視圖形狀的初始化信息
}

viewWillAppear:

控制器的viewWillAppear:在UIViewController對象的視圖即將加入窗口時調用。只要該控制器的view即將要出現,都會調用,在控制器的生命周期中可以調用多次。
而且,如果該方法被調用,就說明視圖一定會出現在屏幕上。

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

viewWillDisappear:

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

- (void)viewWillDisappear:(BOOL)animated
{
    [super viewWillDisappear:animated];
    
    //可執行:
    //1. 記錄滾動視圖的偏移量(因為要記住滾動位置,便于下次查看)
    //2. 存儲數據,便于再次顯示該控制器時使用。
}

屬性字符串Demo


設計需求

  • 布局為TextView下方有四個顏色按鈕,再下方有添加輪廓按鈕和去除輪廓按鈕。
  • 選中TextView的文本后,點擊色彩按鈕,選中的文本的顏色變成點擊的色彩按鈕的背景色。
  • 選中TextView的文本后,點擊添加輪廓,選中的文本增加了輪廓,再點擊色彩按鈕,輪廓變成了相應的顏色。
  • 文本有輪廓的狀態下,點擊去除輪廓按鈕,輪廓消失。
  • 在設置選項來改變系統字體,再回到本Demo界面,字體會做相應改變。

效果圖

屬性字符串效果圖

知識點詳解

屬性字符串的設置

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

設置屬性字符串的一般步驟為:

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

舉個??:


//1. 由現有字符串初始化可變屬性字符串
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];

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

關于按鈕的操作

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

//獲取按鈕當前的標題
self.button.currentTitle

//設定按鈕當前的屬性字符串標題
[self.button setAttributedTitle:title forState:UIControlStateNormal];

屬性字典里的key:

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

獲取TextView被選中的范圍

self.textView.selectedRange

通知機制

為了實現本Demo最后一個需求,我們需要監聽系統字體何時被改變了。所以需要注冊一個能收聽“系統改變”廣播的頻道:

注冊通知:

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

這樣一來,當系統字體發生變化時,注冊該頻道的對象會收到通知并執行自定義的方法。
當改變系統字體的大小后,該類會收到通知,并調用prefredFontsChaged:方法,此時Demo上的字體也要做相應的改變:

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

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

這里,顯然又是一個MVC的流程:系統字體(模型)被改變了,通過廣播(通知)的機制來告訴控制器,然后控制器再調用更改View的方法。還記得在第一篇(詳情請見:斯坦福大學iOS開發公開課總結(一) :iOS的MVC框架)里強調的,從模型到控制器的通信是通過廣播或KVO機制完成的么?

最后的話


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

本文為筆者原創,如需轉載,請事先與筆者交涉~

2016.7.12日更新:


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

本文已在版權印備案,如需轉載請訪問版權印。48422928

獲取授權

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

注意注意?。?!

筆者在近期開通了個人公眾號,主要分享編程,讀書筆記,思考類的文章。

  • 編程類文章:包括筆者以前發布的精選技術文章,以及后續發布的技術文章(以原創為主),并且逐漸脫離 iOS 的內容,將側重點會轉移到提高編程能力的方向上。
  • 讀書筆記類文章:分享編程類,思考類,心理類,職場類書籍的讀書筆記。
  • 思考類文章:分享筆者平時在技術上生活上的思考。

因為公眾號每天發布的消息數有限制,所以到目前為止還沒有將所有過去的精選文章都發布在公眾號上,后續會逐步發布的。

而且因為各大博客平臺的各種限制,后面還會在公眾號上發布一些短小精干,以小見大的干貨文章哦~

掃下方的公眾號二維碼并點擊關注,期待與您的共同成長~

公眾號:程序員維他命
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

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