Swift 3 雜談

swift

Swift 3 出來也有一陣子了,也對(duì)公司的項(xiàng)目做了升級(jí)陪毡,但是暫時(shí)還沒有趕放上線,依舊用著2.3勾扭。相較于Swift 2.2 毡琉, Swift 3做了很大的改動(dòng),逐漸脫離OC的影子妙色。
語法上很多對(duì)象去掉了NS開頭桅滋,去掉了繁瑣的命名。如 UIColor.redColor() 改為 UIColor.red , 變成了屬性身辨,還有方法的第一個(gè)參數(shù)如果不指定 _調(diào)用的時(shí)候也要寫參數(shù)名等等...

本文主要討論Swift 3中的一些坑和使用過程中的一些小技巧丐谋,排名無理由~~


@discardableResult 消除返回值警告

在Swift 3中,如果方法的返回值沒有處理xCode會(huì)報(bào)一個(gè)警告煌珊,如果在方法前加上 @discardableResult 不處理的時(shí)候就不會(huì)有警告了号俐。也可以用
_ = xxx() 來消除警告。


浮點(diǎn)數(shù)取余數(shù)和除法

在Swift 3中 定庵,如果你聲明一個(gè)let m = 12.0 默認(rèn)m是 Double , Double是不能和Float做運(yùn)算的吏饿。CGFloat在32位設(shè)備上是Float32在64位設(shè)備上
Float64 , 所以如果一個(gè)Double和一個(gè)Float做運(yùn)算時(shí)先要轉(zhuǎn)換類型的

let m = 12.0
let n:CGFloat = 19.0

let x = CGFloat(m)/n
let k = m.multiplied(by: Double(n)) // 乘法
let y = m.divided(by: Double(n))    // 除法

但是取余算法是不能作用于浮點(diǎn)型的踪危,如果這樣就會(huì)報(bào)錯(cuò)CGFloat(m)%n
正確的做法是:

let z =  CGFloat(m).truncatingRemainder(dividingBy: n) //取余 12.0

AnyObjectAny

之前整個(gè)項(xiàng)目基本只用 AnyObject 代表大多數(shù)實(shí)例,基本也不和Any有什么交集猪落。因?yàn)镾wift 2 針對(duì)Int贞远、String 等結(jié)構(gòu)體進(jìn)行了轉(zhuǎn)換,編譯器會(huì)自動(dòng)
橋接為NSNumberNSString這種對(duì)象類型 许布,在swift3中AnyObject不能表示結(jié)構(gòu)體了 兴革。而 Any 可以代表 structclass 蜜唾、 func 等幾乎所有類型。

這個(gè)改動(dòng)導(dǎo)致項(xiàng)目很多地方都要隨著改庶艾,而且大多數(shù)庫也做了改變袁余,如Alamofire的參數(shù)從[String:AnyObject]? 變成 [String:Any]?

值得一提的是Any不可以代表任何可空類型,不用指定Any?

栗子:

let str:String? = "xwwa"
var param:[String:Any] = ["x":1,"code":str]
// ["code": Optional("xwwa"), "x": 1]

str 是一個(gè)Optional類型的咱揍,輸出出來也是Optional颖榜。因?yàn)槲覀円郧暗恼?qǐng)求是需要在header中帶參數(shù)的json機(jī)密,換成Any怎么都過不去煤裙,后來發(fā)現(xiàn)有Optional值掩完。

這里寫了個(gè)方法轉(zhuǎn)化了下

func absArray(param:[String:Any])->[String:Any]{
    let res = param.map { (key,value) -> (String,Any?) in
        let newValue = Mirror(reflecting: value)
        if newValue.displayStyle == Mirror.DisplayStyle.optional{
            if let v = newValue.children.first?.value{
                return (key,v)
            }else{
                return (key,nil)
            }
        }
        return (key,value)
    }
    var newParam:[String:Any] = [:]
    res.forEach { (key,v) in
        newParam[key] = v
    }
    return newParam
}
print(absArray(param:param))    // ["code": "xwwa", "x": 1]

用了反射判斷如果值是optional就取出他實(shí)際的值.


Swift 3中 Notification使用方法

extension Notification.Name {
    static let kNoticeDemo = Notification.Name("xx.xx.ww.ss")
}

class DE{
    func test(){
        NotificationCenter.default.post(name: Notification.Name.kNoticeDemo , object: nil)
        NotificationCenter.default.addObserver(self, selector: #selector(demo), name: Notification.Name.kNoticeDemo, object: nil)
        
        NotificationCenter.default.removeObserver(self, name: Notification.Name.kNoticeDemo, object: nil)
    }
    @objc func demo(){
        
    }
}

自定義操作符

在swift 2中自定義操作符

infix operator =~ {
    associativity none
    precedence 130
}

現(xiàn)在在Swift 3中這樣的話會(huì)報(bào)警告Operator should no longer be declared with body;use a precedence group instead

// 自定義操作符 別名類型
infix operator >>> : ATPrecedence
precedencegroup ATPrecedence {
    associativity: left
    higherThan: AdditionPrecedence
    lowerThan: MultiplicationPrecedence
}

直接指定操作符的類型,對(duì)這個(gè)類型進(jìn)行定義硼砰,associativity: left 表示左結(jié)合
higherThan 優(yōu)先級(jí)高于 AdditionPrecedence 這個(gè)是加法的類型
lowerThan 優(yōu)先級(jí)低于 MultiplicationPrecedence 乘除

這里給出常用類型對(duì)應(yīng)的group

  • infix operator || : LogicalDisjunctionPrecedence
  • infix operator && : LogicalConjunctionPrecedence
  • infix operator < : ComparisonPrecedence
  • infix operator <= : ComparisonPrecedence
  • infix operator > : ComparisonPrecedence
  • infix operator >= : ComparisonPrecedence
  • infix operator == : ComparisonPrecedence
  • infix operator != : ComparisonPrecedence
  • infix operator === : ComparisonPrecedence
  • infix operator !== : ComparisonPrecedence
  • infix operator ~= : ComparisonPrecedence
  • infix operator ?? : NilCoalescingPrecedence
  • infix operator + : AdditionPrecedence
  • infix operator - : AdditionPrecedence
  • infix operator &+ : AdditionPrecedence
  • infix operator &- : AdditionPrecedence
  • infix operator | : AdditionPrecedence
  • infix operator ^ : AdditionPrecedence
  • infix operator * : MultiplicationPrecedence
  • infix operator / : MultiplicationPrecedence
  • infix operator % : MultiplicationPrecedence
  • infix operator &* : MultiplicationPrecedence
  • infix operator & : MultiplicationPrecedence
  • infix operator << : BitwiseShiftPrecedence
  • infix operator >> : BitwiseShiftPrecedence
  • infix operator ..< : RangeFormationPrecedence
  • infix operator ... : RangeFormationPrecedence
  • infix operator *= : AssignmentPrecedence
  • infix operator /= : AssignmentPrecedence
  • infix operator %= : AssignmentPrecedence
  • infix operator += : AssignmentPrecedence
  • infix operator -= : AssignmentPrecedence
  • infix operator <<= : AssignmentPrecedence
  • infix operator >>= : AssignmentPrecedence
  • infix operator &= : AssignmentPrecedence
  • infix operator ^= : AssignmentPrecedence
  • infix operator |= : AssignmentPrecedence

合理的使用異常處理且蓬,提高代碼質(zhì)量

在日常開發(fā)中,可能遇到很多特殊情況题翰,使得程序不能繼續(xù)執(zhí)行下去恶阴。有的來自系統(tǒng)語法方面,有的是來自業(yè)務(wù)方面的豹障。這時(shí)候可以使用自定義異常冯事,在底層代碼中不斷throw 在最后一層中去處理。

struct ZError : Error {
    let domain: String
    let code: Int
}

func canThrow() throws{
    let age = 10
    if a < 18{
        let error = ZError(domain: "xxx", code: 990)
        throw error
    }
    
}

do {
    try canThrow()
} catch let error as ZError {
    print("Error: \(error.code) - \(error.domain)") // Error: 990 - xxx
}

是時(shí)候放棄前綴的擴(kuò)展了

以前我們要給UIView擴(kuò)展是這樣的

extension UIView {
    var zz_height:CGFloat{
        set(v){
            self.frame.size.height = v
        }
        get{
            return self.frame.size.height
        }
    }
}

這樣在自己寫的屬性前面加一個(gè)前綴血公。但是Swift 3出來后更多的選擇應(yīng)該是這樣的 view.zz.height 昵仅。 以前kingfisherimageView.kf_setImage
現(xiàn)在變成imageView.kf.setImageSnapKit 也改變成了 make.snp.left 之類的語法

那么怎么寫這樣的擴(kuò)展呢累魔?

這里看了KingFisher的代碼摔笤,給出他的解決方案。比如我們想寫一個(gè)UIView的擴(kuò)展薛夜。


// 寫一個(gè)協(xié)議  定義一個(gè)只讀的類型
public protocol UIViewCompatible {
    associatedtype CompatableType
    var zz: CompatableType { get }
}


public extension UIViewCompatible {
    // 指定泛型類型為自身 籍茧, 自身是協(xié)議 誰實(shí)現(xiàn)了此協(xié)議就是誰了
    public var zz: Auto<Self> {
        get { return Auto(self) } // 初始化 傳入自己
        set { }
    }
}

// Auto是一個(gè)接受一個(gè)泛型類型的結(jié)構(gòu)體 
public struct Auto<Base> {
    // 定義該泛型類型屬性 
    public let base: Base
    public init(_ base: Base) {
        self.base = base
    }
}

// 寫一個(gè)Auto的擴(kuò)展 指定泛型類型是UIView 或者其子類
public extension Auto where Base:UIView {
    
    var height:CGFloat{
        set(v){
            self.base.frame.size.height = v
        }
        get{
            return self.base.frame.size.height
        }
    }
}

// 擴(kuò)展 UIView 實(shí)現(xiàn)  UIViewCompatible 協(xié)議,就擁有了zz屬性 zz又是Auto類型  Auto是用泛型實(shí)例化的  這個(gè)泛型就是UIView了
extension UIView : UIViewCompatible{

}

// 使用

view.zz.height

上面的注釋已經(jīng)盡量詳細(xì)的解釋了這段代碼梯澜,hope you can understand 寞冯!


GCD 的改變

swift 3徹底改變了GCD的使用方式渴析,這里給出日常最基本的幾個(gè)
你不需要在去用 dispatch_get_main_queue ( ) 來獲取主線程,而是 DispatchQueue . main 吮龄,那么要放到主線程的代碼怎么執(zhí)行呢俭茧?只需要在線程后邊使用 . async { } 即可,也就是說漓帚,大概是這樣:

DispatchQueue.main.async {
    print("這里在主線程執(zhí)行")
}
優(yōu)先級(jí)
  • DISPATCH_QUEUE_PRIORITY_HIGH: .userInitiated
  • DISPATCH_QUEUE_PRIORITY_DEFAULT: .default
  • DISPATCH_QUEUE_PRIORITY_LOW: .utility
  • DISPATCH_QUEUE_PRIORITY_BACKGROUND: .background
//global 中設(shè)置優(yōu)先級(jí) 不設(shè)置默認(rèn)是 default
DispatchQueue.global(qos: .userInitiated).async {
    print("設(shè)置優(yōu)先級(jí)")
}

創(chuàng)建一個(gè)隊(duì)列

let queue = DispatchQueue(label: "im.demo.test")

也可以指定優(yōu)先級(jí)和隊(duì)列

let highQueue = DispatchQueue(label: "high.demo.test.queue", qos: DispatchQoS.background , attributes: DispatchQueue.Attributes.concurrent, autoreleaseFrequency: DispatchQueue.AutoreleaseFrequency.inherit , target: nil )

highQueue.async {
    print("ceshi")
}

3秒后執(zhí)行

DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 3.0) {
    print("after")
}

根據(jù)View查找VC

如果你在一個(gè)UITableViewCell 或者 cell上自定義的一個(gè)view上想使用這個(gè)view所在的vc怎么辦母债? 代理 ? 層層引用 尝抖? NO 毡们! 一個(gè)擴(kuò)展解決。
一個(gè)UIView的擴(kuò)展

// 查找vc
func responderViewController() -> UIViewController {
    var responder: UIResponder! = nil
    var next = self.superview
    while next != nil {
        responder = next?.next
        if (responder!.isKind(of: UIViewController.self)){
            return (responder as! UIViewController)
        }
        next = next?.superview
    }
    return (responder as! UIViewController)
}

記得寫在擴(kuò)展中哦昧辽,加上前面的技巧 衙熔。不論你在哪個(gè)view中。只需要這樣let vc = view.zz.responderViewController() 就能拿到所處的vc了搅荞。


View中的第一響應(yīng)者

又是一個(gè)View的擴(kuò)展也很好用红氯,上代碼

func findFirstResponder()->UIView?{
    if self.isFirstResponder{
        return self
    }
    for subView in self.subviews{
        let view = subView.findFirstResponder()
        if view != nil {
            return view
        }
    }
    return nil
}

用法同上,這個(gè)東西能干啥呢咕痛?

利用這個(gè)可以在 NSNotification.Name.UIKeyboardWillShow通知通知中拿到第一響應(yīng)者痢甘,如果第一響應(yīng)者是UITextfield,可以算出局底下的距離茉贡,給擋墻view做變換塞栅。避免被覆蓋。而且這個(gè)東西可以寫在協(xié)議的默認(rèn)實(shí)現(xiàn)中或者
寫在一個(gè)基類中公用块仆。本文為雜談不細(xì)說了构蹬,點(diǎn)到為止咯!


暫時(shí)寫這些吧悔据,后面有時(shí)間再補(bǔ)庄敛。。科汗。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末藻烤,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子头滔,更是在濱河造成了極大的恐慌怖亭,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,743評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件坤检,死亡現(xiàn)場(chǎng)離奇詭異兴猩,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)早歇,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,296評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門倾芝,熙熙樓的掌柜王于貴愁眉苦臉地迎上來讨勤,“玉大人,你說我怎么就攤上這事晨另√肚В” “怎么了?”我有些...
    開封第一講書人閱讀 157,285評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵借尿,是天一觀的道長(zhǎng)刨晴。 經(jīng)常有香客問我,道長(zhǎng)路翻,這世上最難降的妖魔是什么狈癞? 我笑而不...
    開封第一講書人閱讀 56,485評(píng)論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮茂契,結(jié)果婚禮上亿驾,老公的妹妹穿的比我還像新娘。我一直安慰自己账嚎,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,581評(píng)論 6 386
  • 文/花漫 我一把揭開白布儡蔓。 她就那樣靜靜地躺著郭蕉,像睡著了一般。 火紅的嫁衣襯著肌膚如雪喂江。 梳的紋絲不亂的頭發(fā)上召锈,一...
    開封第一講書人閱讀 49,821評(píng)論 1 290
  • 那天,我揣著相機(jī)與錄音获询,去河邊找鬼涨岁。 笑死,一個(gè)胖子當(dāng)著我的面吹牛吉嚣,可吹牛的內(nèi)容都是我干的梢薪。 我是一名探鬼主播,決...
    沈念sama閱讀 38,960評(píng)論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼尝哆,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼秉撇!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起秋泄,我...
    開封第一講書人閱讀 37,719評(píng)論 0 266
  • 序言:老撾萬榮一對(duì)情侶失蹤琐馆,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后恒序,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體瘦麸,經(jīng)...
    沈念sama閱讀 44,186評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,516評(píng)論 2 327
  • 正文 我和宋清朗相戀三年歧胁,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了滋饲。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片厉碟。...
    茶點(diǎn)故事閱讀 38,650評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖了赌,靈堂內(nèi)的尸體忽然破棺而出墨榄,到底是詐尸還是另有隱情,我是刑警寧澤勿她,帶...
    沈念sama閱讀 34,329評(píng)論 4 330
  • 正文 年R本政府宣布袄秩,位于F島的核電站,受9級(jí)特大地震影響逢并,放射性物質(zhì)發(fā)生泄漏之剧。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,936評(píng)論 3 313
  • 文/蒙蒙 一砍聊、第九天 我趴在偏房一處隱蔽的房頂上張望贴谎。 院中可真熱鬧,春花似錦焚挠、人聲如沸璃吧。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,757評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽帘腹。三九已至,卻和暖如春许饿,著一層夾襖步出監(jiān)牢的瞬間阳欲,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,991評(píng)論 1 266
  • 我被黑心中介騙來泰國(guó)打工陋率, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留球化,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,370評(píng)論 2 360
  • 正文 我出身青樓瓦糟,卻偏偏與公主長(zhǎng)得像筒愚,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子狸页,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,527評(píng)論 2 349

推薦閱讀更多精彩內(nèi)容