iOS 11 的一些玩意兒: Swift 4

iOS 11九月份就要正式發佈了。拖延症表示陸陸續續還沒看完WWDC~?。除了重磅的ARKitCore ML,其餘更像是小修小補。連Swift 4都不是一門新語言,算什麼WWDC~~~ios

陸陸續續寫一些iOS 11的玩意兒吧~git

這是關於Swift 4的~~~~github

Access Control

想給Swift跪了~~~json

Swift麼有Objective-C.h.m這樣涇渭分明,哪些該露點的,哪些不應露點的,都很清晰。因而在Swift中有了access control,就是public啊,private啊,fileprivate啊等。swift

Swift 4中,主要是對private進行從新定義。在Swift 3中,private代表的屬性和方法,是沒法在extension中使用的,只有fileprivate才能夠。可是~~~,Swift 4以爲不太合理,因此,private能夠在extension中使用了~~~仍是上個?吧。。數組

struct Foo {
    private let a : Int
    fileprivate let b : Int
    private func testA() {}
    fileprivate func testB() {}
}

extension Foo {
    func testAB() {
        print(a)        // private 標註的 a 屬性,在 Swift 3 中是沒法使用的
        print(b)
        testA()         // private 標註的 testA 方法,在 Swift 3 中是沒法使用的
        testB()
    }
}

dynamic

Swift 3dynamic是自帶@objc,可是Swift 4中,dynamic不在包含@objc了。因此有些須要使用到@objc標明的方法,在Swift 4得補回去。以前爲了讓Swift可使用JSPatch,因而乎,給一些方法都加了dynamic~~~~累cry~~安全

Swift & Objective-C

直接上個?。app

class Foo {
    let a : Int
    func testA() {}
}

Swift 3中,若是是在Objective-C中使用上述的代碼,那麼是能夠成功調用到foo.a[foo testA]的。在對應的xxx-Swift.h文件中,也能夠看到相關的轉換成Objective-C的代碼。可是!!!在Swift 4,這些都不成立了。若是要使用,那麼須要標上@objcMembers或者@objc。也就是——編碼

class Foo {
    @objcMembers let a : Int
       @objcMembers func testA() {}
   // 又或者
   @objc let b : Int
       @objc func testB() {}
}

不過,文檔更推薦使用@objcMembers。據悉,@objc相對於@objcMembers而來,可能會增大包的編譯大小。並且,最好是在須要使用到的地方纔用上@objcMembers,而不是全部都標明~~code

NSAttributedString

先前,諸如相似NSFontAttributeName,NSForegroundColorAttributeName等這些,在Swift 4中,通通變成NSAttributedStringKey.font,NSAttributedStringKey.foregroundColor等這些更佳Swift化的形式了。

String

字符串長度

Swift 3 Swift 4
"xxx".characters.count "xxx".count

換行

// Swift 3 換行須要用到換行符 \n
let str = "xxx\nxxx"

// Swift 4 有了更方便的表示。使用 """ 。不過得保持一致的縮進
let str = """
            xxx
            xxx
            """

split

這方法是進行切割字符串的。看?!

var str = "Hello, playground"
let strArr = str.split(separator: ",") // ["Hello","playground"]

可是切割獲得的數組是[SubString]。所以,在賦值的時候,須要對其進行強轉,即String(SubString)這樣。

Codable

Swift 4中,加入了Codable協議,能夠將JSON給轉換成對應的Struct或者Class,也能夠將其餘的格式轉成對應的。

Codabel是由DecodableEncodable兩個協議組成的。

public typealias Codable = Decodable & Encodable

直接上?。

let jsonStr = """
       {
            "id": 123455,
            "nickname": "Ben",
            "isMale": true,
            "birthday": "2000年3月24日",
            "personalURL": "https://addicechan.github.io"
        }
        """
let jsonData = jsonStr.data(using: .utf8)!
let decoder = JSONDecoder()
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "YYYY年MM月dd日"
decoder.dateDecodingStrategy = .formatted(dateFormatter)
do {
    let user = try decoder.decode(User.self, from: jsonData)
    print(user)
    print(user.personalURL.scheme ?? "http?https?")
} catch let error {
    print(error.localizedDescription)
}

使用上,並不困難。使用JSONDecoder能夠對一些時間格式進行處理,好比上述?就是自定義時間格式。固然還能夠用時間戳顯示等。dateDecodingStrategy屬性是一個DateDecodingStrategy枚舉值來着。具體瞅文檔吧。

能夠解碼,固然也能夠進行編碼。

// 接着???的?
let user1 = User(id: 1000,
                 nickname: "ADDICE",
                 isMale: true,
                 birthday: Date(),
                 personalURL: URL(string: "https://addicechan.github.io")!)
                 
let encoder = JSONEncoder()
encoder.dateEncodingStrategy = .formatted(dateFormatter)
do {
    let data = try encoder.encode(user1)
    let str = String.init(data: data, encoding: .utf8)!
    print(str)
} catch let encodeError {
    print(encodeError.localizedDescription)
}

有了Codable,對JSON格式的轉換也是方便不少。不過實際在項目中使用仍是有待驗證吧。不過這卻是解決了以前Swift原生代碼對JSON數據的解析,不用各類嵌套。反正,使用這個協議還能夠支持其餘數據格式,並非單單JSON一種。

KVC

class Foo: NSObject {
    @objc var age : Int
    var name : String
    init(age: Int, name: String) {
        self.age = age
        self.name = name
    }
}
let foo = Foo(age: 10, name: "foo")
#if swift(>=4.0)
    let key = \Foo.age
    foo[keyPath: key] = 50
    print(foo[keyPath: \ Foo.name])
#else
    let key = #keyPath(Foo.age)
    foo.setValue(20, forKey: key)
#endif
print(foo.age)

較之Swift 3#keyPath(T.property)這種方式,Swift 4用一個\去表示一個keyPath,並且具有各類推斷,而且還能夠用於structSwift是一門強類型的安全語言,因此使用改版後的KeyPath能夠推斷到原來的類型,而不是再是Any。不過,先前用#keyPath這種生成字符串的方式,竟然沒有被廢除~?

KeyPath的基類是AnyPathAnyPath擁有rootTypevalueType。根據上述的?,那麼key的類型其實應該是KeyPath<Foo, Int>。也就是,若是你要取到Foo.age,其實也能夠這樣去寫——

let key : KeyPath<Foo, Int> = \Foo.age

可是不少時候,咱們會選擇使用推導類型,因此仍是懶一些吧。

其實按照文檔來講,KeyPath的層級式這樣的。

說明
AnyPath 基類,用RootValue屬性,以及appending(path: AnyKeyPath)能夠進行拼接keyPath
PartialKeyPath<Root> 繼承自AnyPath,只聲明瞭Root類型,Value 均爲Any
KeyPath<Root,Value> 繼承自PartialKeyPath,攜帶了RootValue,都有明確的類型
WritableKeyPath<Root,Value> 繼承自KeyPath,可讀可寫,用於struct這種值類型。
ReferenceWritableKeyPath<Root,Value> 繼承自WritableKeyPath,可讀可寫,用於class這種引用類型。

另外,發現一個bug。當用KeyPath去更改struct裏面的值時,只能讀,不能寫。可是WWDCkeynote顯示又是可讀可寫。。寂寞。不知道是否是Debug版本的鍋。反正我用的是Xcode 9 beta 6

上個WWDC上面的那個?。

@objcMembers
class Kid : NSObject {
    dynamic var nickname: String = ""
    dynamic var age: Double = 0.0
    dynamic var bestFriend: Kid? = nil
    dynamic var friends: [Kid] = []
    init(nickname: String, age: Double) {
        super.init()
        self.nickname = nickname
        self.age = age
    }
}

struct BirthdayParty {
    let celebrant: Kid
    var theme: String
    var attending: [Kid]
}
let ben = Kid(nickname: "Benji", age: 5.5)

var bensParty = BirthdayParty(celebrant: ben, theme: "Construction", attending: [])

let birthdayKid = bensParty[keyPath: \BirthdayParty.celebrant]

bensParty[keyPath: \BirthdayParty.theme] = "Pirate"

KVO

當須要監聽對象某個屬性的時候,一般咱們會使用KVO的方式,利用addObserver來添加觀察者,以後在

func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?)

進行處理。可是,Swift 4有了更加簡單的觀察形式。

// 方式一
// observer 爲 被觀察的對象,keyValueChange 爲被觀察的屬性的變化
foo.observe(\FooClass.age, options: .new, changeHandler: { (observer, keyValueChange) in 
})

// 方式二
foo.observe(\FooClass.age, changeHandler: { (observer, keyValueChange) in
    
})

Swift 4大體上整理到這些。還有其餘的一些更新。推薦仍是看官方文檔。上述的內容,估計也會有遺漏,或者錯誤。請多包涵~?

Demo在此~~~

相關文章
相關標籤/搜索