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
AnyObject
、Any
之前整個(gè)項(xiàng)目基本只用 AnyObject
代表大多數(shù)實(shí)例,基本也不和Any
有什么交集猪落。因?yàn)镾wift 2 針對(duì)Int
贞远、String
等結(jié)構(gòu)體進(jìn)行了轉(zhuǎn)換,編譯器會(huì)自動(dòng)
橋接為NSNumber
和NSString
這種對(duì)象類型 许布,在swift3中AnyObject
不能表示結(jié)構(gòu)體了 兴革。而 Any
可以代表 struct
、 class
蜜唾、 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
昵仅。 以前kingfisher
是 imageView.kf_setImage
現(xiàn)在變成imageView.kf.setImage
。SnapKit
也改變成了 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ǔ)庄敛。。科汗。