Storyboard/Xib 進階教程

引言:

2007年第一部iPhone問世後,智能手機開始了取代PC終端的腳步。

時間來到2016年。

在時代巨浪的推動下,如今,移動互聯網已然成爲了IT領域的主戰場。今天的iOS應用程序已經再不是從前那簡單、嬌小的弱女子了。手機淘寶、網易海購等原生和Html5結合的超級App層出不窮。Hybrid模式大紅大紫,卻也先天不足。

在iOS開發領域,我一直鍾愛IB。

IB的源代碼由Xml所書寫,生澀難讀,難以駕馭。

所以,IB開發幾乎都是在圖形化界面中進行的。

但這卻並未妨礙IB成爲iOS開發中最具效率的開發方式。

至於箇中原因,還是Xcode強大的GUI操作界面和IB靈活的 Runtime注入,AutoLayout簡潔的適配設置,SizeClass的iPhone/iPad兼容設置。

有時我在想,如果將IB的源代碼進化成Html5風格書寫會有什麼樣的一番風景呢。

在我眼中,以IB書寫界面爲主流的iOS開發模式,是最有可能進化成爲完美的Hybrid模式,試想一下,兼容H5的IB配合Xcode強大的IDE編輯器,會帶來一種何等愉悅的開發體驗,會產生一種何等優異的Hybrid模式。性能優異,界面動態,有序的將邏輯放在前端和後端。這纔是我心目中的Hybrid—既可以輕鬆的隨App一起打包,還擁有卓越的性能,又可以隨時對界面進行動態替換。

從iOS App 支持通過Tag標記來延遲下載IB文件可以得出 ,這在技術實現上不會有任何問題。

可是一心要控制App的性能和質量的Apple會大開綠燈嗎?

短期內應該不會,但動態界面,固定邏輯也許會成爲可能。

好了,說了這麼多,我們也應該開始今天的主題了。

第一章:常見崩潰排查

連awakeFromeNib都沒有執行,程序卻崩潰了

連viewDidLoad都沒有執行,程序還是崩潰了

這個 控件/界面 纔剛一使用,程序就已經崩潰了

只是改變一點看起來沒有任何問題的layout,程序崩潰了

合併代碼後我的IB文件突然打不開了

沒有任何報錯,沒有任何警告,程序崩潰了,IB,IB,真真是讓人又愛又恨


相信許多入行iOS開發不久,或者使用IB不久的朋友都有遇到過這樣的問題。這也是很多朋友放棄在實際項目中使用IB的原因之一。

IB彷彿是一把雙刃劍,極大的提升開發效率,有着優異視圖解耦性,卻也伴隨着難纏的故障排查。

如果就到此而止了,您還會繼續使用IB嗎?


我想絕大部分開發者會放棄它,或者只使用Xib而放棄Storyboard,尤其是站在生產第一線的朋友們。

在實際開發中我也常常遇到這樣的朋友,因爲這樣或者那樣的原因而棄用了IB,或者僅僅用IB搭建了View,卻用代碼給它設置一切。

在我們實際開發中,如果不使用IB,或者不部分使用Storyboard,在開發效率上,明顯會慢於有着AndroidStudio加成的Android player。

這讓一向自稱程序高富帥的我們情何以堪。


好了,言歸正轉。


常見崩潰點:


1、Terminating app due to uncaught exception ‘NSUnknownKeyException'

-IB控件關聯代碼錯誤


問題描述:


控件關聯對象或者事件(拉線到代碼)後,移除了代碼中的(對象或者方法)卻沒有移除控件上的引用(Referencing)。此種情況必崩。


解決方案:


如果同一IB文件控件較少:


方案,展開IB右邊工具欄,切換到 Connection Inspector(帶箭頭那個)。切換點擊控件逐一排查 Referencing,先檢查同一控件有無重複Referencing(通常情況下是更改了代碼中的關聯對象,而IB中沒有移除原有的Referencing導致),如果有重複Referencing再檢查哪一個是真正對應代碼的Referencing。如果沒有找到問題,再檢查是否所有的關聯在代碼中都有對應的存在(包括事件 和方法)。



2、reason: [<UI*** 0x15550640> setValue:forUndefinedKey:]: this class is not key value coding-compliant for the key

-IB keyPath 設置錯誤(如果沒用過keyPath參考 http://blog.csdn.net/bsn1928/article/details/51372197


問題描述:


控件設置了不存在的keyPath。或者不應該設置KeyPath的控件被設置了KeyPath。

此種情況必崩。


解決方案:


如果同一IB文件控件較少,使用方案1,反之使用方案2:


方案1,展開IB右邊工具欄,切換到 Identity Inspector(方框帶文檔圖標那個)。展開User Defiend Runtime Attributes,找到錯誤提示中這段代碼 [<UI*** 0x15550640> setValue:forUndefinedKey:] 的鍵,按類名逐一檢查Key Path是否爲空,然後修復之。


方案2,右鍵 IB 文件 Open As -> Source Code。Command + F搜索  KeyPath=“” 。如果未找到,找到錯誤提示中這段代碼 [<UI*** 0x15550640> setValue:forUndefinedKey:] 的鍵,按類名搜索之,逐一排查,是否設置了無法找到的KeyPath。找到後,移除此KeyPath即可修復(注:源代碼中要按鍵值對刪除,否則將無法編譯通過,至於爲什麼,玩過Html的都應該知道)。(當然你也可以寫個腳本來完成如此複雜的操作,這裏只闡述原理)



第二章:利用IBDesignable創建自定義IB控件

1、準備:Xcode 7.* +

這裏介紹一下Label控件的自定義,其它控件以此類推。

新建Swift工程IBExtension,新建 IBLabel 繼承自 UILabel。在類開始前加入

@IBDesignable

代碼如下


//  在OC中 IB_Designable

//  在OC中 IBInspectable


import UIKit


@IBDesignable

class IBLabel: UILabel {

    @IBInspectable var cornerRadius:CGFloat = 0{

        didSet{

            layer.cornerRadius = cornerRadius

            layer.masksToBounds = cornerRadius > 0

        }

    }

    @IBInspectable var borderWidth:CGFloat = 0{

        didSet{

            layer.masksToBounds = cornerRadius > 0

            layer.borderWidth = borderWidth

        }

    }

    @IBInspectable var borderColor:UIColor?{

        didSet{

            layer.masksToBounds = borderColor != nil

            layer.borderColor = borderColor?.CGColor

        }

    }

    @IBInspectable var allowSelected:Bool = false{

        didSet{

            if  allowSelected{

                userInteractionEnabled = true

                addGestureRecognizer(tap)

            }

            else{

                isSelected = false

                userInteractionEnabled = false

                removeGestureRecognizer(tap)

            }

        }

    }

    @IBInspectable var hiddenBorderWhenSelected = false{

        didSet{

            if hiddenBorderWhenSelected {layer.borderWidth = 0}

            else {layer.borderWidth = borderWidth}

        }

    }

    @IBInspectable var isSelected:Bool = false{

        didSet{

            if !allowSelected{

                backgroundColor = normalBackgroundColor

                textColor = normalTextColor

                return

            }

            if isSelected{

                backgroundColor = selectedBackgroundColor

                textColor = selectedTextColor

                if hiddenBorderWhenSelected {layer.borderWidth = 0}

            }

            else{

                backgroundColor = normalBackgroundColor

                textColor = normalTextColor

                if hiddenBorderWhenSelected {layer.borderWidth = borderWidth}

            }

        }

    }

    @IBInspectable var normalTextColor:UIColor?

    @IBInspectable var selectedTextColor:UIColor?

    @IBInspectable var normalBackgroundColor:UIColor?

    @IBInspectable var selectedBackgroundColor:UIColor?

    lazy var tap:UITapGestureRecognizer = {

        let tapGesture = UITapGestureRecognizer()

        tapGesture .addTarget(self, action: #selector(IBLabel.didSelected(_:)))

        return tapGesture

    }()

    func didSelected(gesture:UITapGestureRecognizer) {

        isSelected = !isSelected

    }

}


打開IB新建Label 展開IB右邊工具欄,切換到 Identity Inspector 在 Class 類中輸入我們剛纔創建的IBLabel

然後切換到 Attributes Inspector 這時你可以看到你的自定義屬性

如果你成功了

你會感受到IB突然變得如此的強大

如果失敗了

不要着急,點擊 Editor->Automaticaly Referesh View

然後再切換回來

如果還不行

沒關係,重啓Xcode



第三章:使用Storyboard創建靜態列表,並配置動態刷新方法(下期再講解)






發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章