iOS開發(fā)技巧系列---使用鏈?zhǔn)骄幊毯虰lock來實(shí)現(xiàn)UIAlertView

UIAlertView是iOS開發(fā)過程中最常用的控件之一,是提醒用戶做出選擇最主要的工具.在iOS8及后來的系統(tǒng)中,蘋果更推薦使用UIAlertController來代替UIAlertView.所以本文也并不提倡開發(fā)者再使用UIAlertView,
本文的目的是探討如何將原來的給變量賦值和通過Delete來回調(diào)的方式變成鏈?zhǔn)骄幊田L(fēng)格和通過Block來回調(diào).通過學(xué)習(xí)對UIAlertView的改造讓各位iOS開發(fā)者能夠?qū)W會這種更加便捷的開發(fā)方式

2018年Swift4已經(jīng)發(fā)布,現(xiàn)在需要更新這些文章了,我也不再使用UIAlertView。但是其鏈?zhǔn)骄幊痰暮诵乃枷霙]有變過,使用UIAlertController一也可以改出鏈?zhǔn)骄幊痰男Ч鰜怼N野堰@些代碼都放在iOSDemo項(xiàng)目里
https://github.com/DuckDeck/iOSDemo Library的 GrandCue里面。

什么是鏈?zhǔn)骄幊?/h3>

對于有一定開發(fā)經(jīng)驗(yàn)的開發(fā)者來說,鏈?zhǔn)骄幊滩⒉荒吧?有很多知名的開源庫使用了這種編程風(fēng)格,比如大名鼎鼎的JQuery,而iOS庫中,Masory和Snapkit也是典型的使用鏈?zhǔn)骄幊痰睦?
大體來說,鏈?zhǔn)骄幊叹褪菍⒍鄠€操作(多行代碼)通過某種操作符(通常是點(diǎn)號.)鏈接成一句的代碼.便代碼更加緊湊,可讀性也更好,降低了代碼的重復(fù)度.比如以下代碼:

//使用普通的賦值模式
txtUserName.placeHolder = "請輸入用戶名"
txtUserName.font = UIFont.systemFont(15)
txtUserName.textColor = UIColor.GrayColor()
//使用鏈?zhǔn)骄幊痰恼Z句
txtUserName.setPlaceHolder("請輸入用戶名").setFont(15).setTextColor(UIColor.GrayColor())

通過這個例子讀者應(yīng)該可以更清楚的了解什么是鏈?zhǔn)骄幊田L(fēng)格.簡單來說,鏈?zhǔn)骄幊田L(fēng)格要有以下特點(diǎn)

  • 通常是都是調(diào)用一個函數(shù)來給屬性賦值.也就是說,該函數(shù)封裝了賦值的語句,還可以在里面加入自己的判斷和一些邏輯.
  • 該函數(shù)必須有一個返回值,通常是它本身.也可以是處理后的數(shù)據(jù)或者對象.
  • 可以用靜態(tài)函數(shù)作為起始函數(shù),但是后面的全是實(shí)例函數(shù).
  • 可以設(shè)定一個最終函數(shù),該函數(shù)不返回任何對象,用它來完全最后所有操作.

鏈?zhǔn)骄幊痰睦?/h3>

使用鏈?zhǔn)骄幊套钪饕暮锰幨强梢允勾a更簡潔,寫起來一種"爽快"感.設(shè)計(jì)優(yōu)秀的鏈?zhǔn)骄幊炭梢源蟠蠼档椭貜?fù)的代碼,增強(qiáng)邏輯感.不足之處就是對開
發(fā)者的業(yè)務(wù)邏輯能力要求較高,同時因?yàn)殒準(zhǔn)骄幊潭际钦{(diào)用函數(shù),所以有可能會造成過深的函數(shù)調(diào)用棧.稍微影響性能.

使用Block來回調(diào)UIAlertView的Delegate

iOS開發(fā)中有很多回調(diào)都是使用Delegate完成的,相信各位讀者已經(jīng)寫過很多次了.相對來說,使用Delegate比較繁瑣,有時還需要在Delegate里
判斷是哪個對象的Delegate,優(yōu)點(diǎn)是運(yùn)行效率較高.而Block則相反,寫起來更直觀,開發(fā)效率更高.蘋果也是逐步使用Block來代替Delegate,iOS
8最新的UIViewController里的Action已經(jīng)全部使用Block來實(shí)現(xiàn).而且Swift里的閉包,匿名函數(shù)更上比比皆是.所以大膽地使用Block來代替
Delegate和Target-Action吧,蘋果會幫我們處理好各種性能問題的.但是需要注意的是retian-circle問題,初識Block很容易出現(xiàn)這種問題.

使用鏈?zhǔn)骄幊毯虰lock來改造UIAlertView

目前有兩種方式可以實(shí)現(xiàn)將UIAlertView的Delegate改成Block的回調(diào),一是使用運(yùn)行時給UIAlertView加上Block屬性.二是再寫一個新的類繼承
UIAlertView,本文使用的是第二種方式,寫起來更簡單一點(diǎn).

先定義一個新的類來繼承UIAlertView,并且實(shí)現(xiàn)UIAlertViewDelegate協(xié)議
class BlockAlert:UIAlertView,UIAlertViewDelegate{
    var completion:((buttonIndex:Int,alert:UIAlertView)->Void)? //定義各個Block用來回調(diào),其參數(shù)名和Delegate回調(diào)的函數(shù)參數(shù)名一至
    var willDismissBlock:((buttonIndex:Int,alert:UIAlertView)->Void)?
    var didDismissBlock:((buttonIndex:Int,alert:UIAlertView)->Void)?
    var didPresentBlock:((alert:UIAlertView)->Void)?
    var willPresentBlock:((alert:UIAlertView)->Void)?
    var alertWithCancelBlock:((alert:UIAlertView)->Void)?
    override init(frame: CGRect) {
        super.init(frame: frame)
        self.delegate = self //將delegate設(shè)為自己
    }
    func alertView(alertView: UIAlertView, clickedButtonAtIndex buttonIndex: Int) {
        if let block = completion{ //最主要的Block,當(dāng)用戶點(diǎn)了按鈕時回調(diào),先要判斷這個Block存在不?
            block(buttonIndex: buttonIndex, alert: alertView)
        }
    }
    func alertView(alertView: UIAlertView, didDismissWithButtonIndex buttonIndex: Int) {
        if let block = didDismissBlock{//其他根據(jù)相應(yīng)的Delegate回調(diào)函數(shù)依次調(diào)用各個Block
            block(buttonIndex: buttonIndex, alert: alertView)
        }
    }
    func alertView(alertView: UIAlertView, willDismissWithButtonIndex buttonIndex: Int) {
        if let block = willDismissBlock{
            block(buttonIndex: buttonIndex, alert: alertView)
        }   
    }
    // 其他幾個委托方法也省略了,原理都是一樣的
    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}

參考上面的代碼,總體思路是在構(gòu)造器里面將委托設(shè)為自己,再將Delegate里面所有的函數(shù)用Block來實(shí)現(xiàn),Block里面的參數(shù)和委托回調(diào)的函數(shù)參數(shù)一至.當(dāng)有委托函數(shù)回調(diào)時,先判斷這個
Block是不是nil,如果不是,則執(zhí)行該Block
接下來的操作就很容易了

再直接擴(kuò)展UIAlertView,加上自己想要的鏈?zhǔn)骄幊毯瘮?shù)
extension UIAlertView {
    static func setMessage(msg:String)->UIAlertView{//在這里設(shè)定這個為靜態(tài)函數(shù),在里面實(shí)例化一個BlockAlert對象,再返回該對象
        let alert = BlockAlert()
        alert.message = msg
        return alert
    }
    
    func addAlertStyle(style:UIAlertViewStyle)->UIAlertView{ //直接在各個函數(shù)中封裝一些操作.再返回自身
        self.alertViewStyle = style
        return self
    }
    
    func addTitle(title:String)->UIAlertView{
        self.title = title
        return self
    }
    
    func addFirstButton(btnTitle:String)->UIAlertView{
        self.addButtonWithTitle(btnTitle)
        return self
    }
    
    func addSecondButton(btnTitle:String)->UIAlertView{
        self.addButtonWithTitle(btnTitle)
        return self
    }
    
    func addButtons(btnTitles:[String])->UIAlertView{
        for title in btnTitles{
            self.addButtonWithTitle(title)
        }
        return self
    }
    
    func addButtonClickEvent(clickButton:((buttonIndex:Int,alert:UIAlertView)->Void)?)->UIAlertView{
        if let alert = self as? BlockAlert{//對于block,先要判斷它是不是BlockAlert,如果是的話才添加該block,后面都是這種操作
            alert.completion = clickButton
        }
        return self
    }
    
    //這里也是省略了部分函數(shù),因?yàn)樵矶际且粯拥?    func addAlertCancelEvent(event:((alert:UIAlertView)->Void)?)->UIAlertView{
        if let alert = self as? BlockAlert{
            alert.alertWithCancelBlock = event
        }
        return self
    }
    
    
    func alertWithButtonClick(clickButton:((buttonIndex:Int,alert:UIAlertView)->Void)?){
        if let alert = self as? BlockAlert{ //這個為終結(jié)函數(shù),沒有返回值,在里面直接調(diào)用了show()方法.
            alert.completion = clickButton
            alert.show()
        }
    }
}

在這里面我選擇了用UIAlverView來擴(kuò)展,而不是BlockAlert,這樣可能會導(dǎo)致開發(fā)過程中踩進(jìn)陷阱.因?yàn)樵谑讉€靜態(tài)函數(shù)返回的對象是一個BlockAction對象,而不是UIAlertView對象
在后面添加Block時先要判斷本身是不是BlockAction對象,如果是的話再將設(shè)定Block,所以在開發(fā)過程中要小心這個陷阱.當(dāng)然讀者也可以直接擴(kuò)展BlockAlert,這樣會更安全一些.

最后直接使用靜態(tài)函數(shù)加鏈?zhǔn)骄幊虂韽棾鯝lert
UIAlertView.setMessage("這里要設(shè)置信息").addTitle("我是標(biāo)題").addFirstButton("取消").addSecondButton("確認(rèn)").alertWithButtonClick { (buttonIndex, alert) -> Void in
            print("你按下了第\(buttonIndex)個按鍵")
            //你按下了第1個按鍵
            //你按下了第0個按鍵
        }

如果要使用其他的委托方法也很簡單

   UIAlertView.setMessage("這里要設(shè)置信息").addTitle("我是標(biāo)題").addFirstButton("取消").addSecondButton("確認(rèn)").addWillPresentEvent { (alert) in
             print("the alertView will present")
        }.addDidPresentEvent { (alert) in
            print("the alertView did present")
        }.alertWithButtonClick { (buttonIndex, alert) in
              print("你按下了第\(buttonIndex)個按鍵")
        }

當(dāng)然其他的一些自定義樣式,或者是帶用戶名輸入和密碼輸入框的也很簡單

   UIAlertView.setMessage("這里要設(shè)置信息").addTitle("我是標(biāo)題").addFirstButton("取消").addSecondButton("確認(rèn)").addAlertStyle(.LoginAndPasswordInput).addDidPresentEvent { (alert) in
            print("the alertView did present")
        }.alertWithButtonClick { (buttonIndex, alert) in
            let txt1 = alert.textFieldAtIndex(0)?.text
            let txt2 = alert.textFieldAtIndex(1)?.text
            print("userName:\(txt1) password:\(txt2)")
            //打印出the alertView did present
            //userName:Optional("111") password:Optional("222")
        }
帶用戶名密碼的Alert

可見,使用鏈?zhǔn)骄幊碳覤lock的方式基本只需要短短幾行代碼就可以滿足大部分使用UIAlertView的使用場景,寫起來很方便快捷.對于UIActionSheet也一樣,可以將其完全改造成使用鏈?zhǔn)骄幊碳覤lock的形式來使用.這個便留給讀者
來完成了.相信看完上面的代碼并實(shí)踐過的讀者很快就可以寫出來.以上所有代碼都可以在我的Github的iOSDemo項(xiàng)目里有所有的示例:
https://github.com/DuckDeck/iOSDemo Library的 GrandCue里面。關(guān)于UIAlertView的代碼我都刪除了,而是用UIAlertController來作為示例。
因?yàn)楝F(xiàn)在Apple還是更推薦開發(fā)者使用最新的UIAlertController,它的API設(shè)計(jì)和UIAlertView是完全不同的.改成了基于Block的回調(diào)方式,使用起來更方便了.在這里這篇文章給大家詳細(xì)地介紹了
UIAlertController詳解,有興趣的讀者可以去看看

總結(jié)

本文用一個足夠簡單的例子和大家探討了怎么將原先使用UIAlertView編程方式改造成基于鏈?zhǔn)骄幊毯蚥lock的編程方式.但是在實(shí)際的開發(fā)過程中,情況要比這個復(fù)雜得多,首先要考慮該業(yè)務(wù)和邏輯適不適合使用鏈?zhǔn)骄幊?其次設(shè)計(jì)出良好的
鏈?zhǔn)骄幊藺PI也是需要花費(fèi)很大精力的.函數(shù)返回值的設(shè)計(jì)也是很需要功力的,因?yàn)樗苯佑绊懥讼乱粋€調(diào)用函數(shù).

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

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

  • 【步驟一】vi 文件名.txt 比如創(chuàng)建文件file.txt,用vi file.txt即可,如下圖 【步驟二】:w...
    pinggushi閱讀 1,006評論 0 0
  • 文/07 懷恨 最恨相思寄隔岸 朝夕相望無究嘆 伊人行醫(yī)忙鄉(xiāng)途 冷落癡漢心不甘 無聊無趣無奈何 無情無眠無風(fēng)波 無...
    723edf844d12閱讀 253評論 3 10

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