iOS 11
九月份就要正式發佈了。拖延症表示陸陸續續還沒看完WWDC
~?。除了重磅的ARKit
和Core ML
,其餘更像是小修小補。連Swift 4
都不是一門新語言,算什麼WWDC
~~~ios
陸陸續續寫一些iOS 11
的玩意兒吧~git
這是關於Swift 4
的~~~~github
想給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() } }
Swift 3
中dynamic
是自帶@objc
,可是Swift 4
中,dynamic
不在包含@objc
了。因此有些須要使用到@objc
標明的方法,在Swift 4
得補回去。以前爲了讓Swift
可使用JSPatch
,因而乎,給一些方法都加了dynamic
~~~~累cry~~安全
直接上個?。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
先前,諸如相似NSFontAttributeName
,NSForegroundColorAttributeName
等這些,在Swift 4
中,通通變成NSAttributedStringKey.font
,NSAttributedStringKey.foregroundColor
等這些更佳Swift
化的形式了。
Swift 3 | Swift 4 |
---|---|
"xxx".characters.count | "xxx".count |
// Swift 3 換行須要用到換行符 \n let str = "xxx\nxxx" // Swift 4 有了更方便的表示。使用 """ 。不過得保持一致的縮進 let str = """ xxx xxx """
這方法是進行切割字符串的。看?!
var str = "Hello, playground" let strArr = str.split(separator: ",") // ["Hello","playground"]
可是切割獲得的數組是[SubString]
。所以,在賦值的時候,須要對其進行強轉,即String(SubString)
這樣。
Swift 4
中,加入了Codable
協議,能夠將JSON
給轉換成對應的Struct
或者Class
,也能夠將其餘的格式轉成對應的。
Codabel
是由Decodable
和Encodable
兩個協議組成的。
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
一種。
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
,並且具有各類推斷,而且還能夠用於struct
。Swift
是一門強類型的安全語言,因此使用改版後的KeyPath
能夠推斷到原來的類型,而不是再是Any
。不過,先前用#keyPath
這種生成字符串的方式,竟然沒有被廢除~?
KeyPath
的基類是AnyPath
。AnyPath
擁有rootType
和valueType
。根據上述的?,那麼key
的類型其實應該是KeyPath<Foo, Int>
。也就是,若是你要取到Foo.age
,其實也能夠這樣去寫——
let key : KeyPath<Foo, Int> = \Foo.age
可是不少時候,咱們會選擇使用推導類型,因此仍是懶一些吧。
其實按照文檔來講,KeyPath
的層級式這樣的。
類 | 說明 |
---|---|
AnyPath | 基類,用Root 和Value 屬性,以及appending(path: AnyKeyPath) 能夠進行拼接keyPath |
PartialKeyPath<Root> | 繼承自AnyPath ,只聲明瞭Root 類型,Value 均爲Any |
KeyPath<Root,Value> | 繼承自PartialKeyPath ,攜帶了Root 和Value ,都有明確的類型 |
WritableKeyPath<Root,Value> | 繼承自KeyPath ,可讀可寫,用於struct 這種值類型。 |
ReferenceWritableKeyPath<Root,Value> | 繼承自WritableKeyPath ,可讀可寫,用於class 這種引用類型。 |
另外,發現一個bug
。當用KeyPath
去更改struct
裏面的值時,只能讀,不能寫。可是WWDC
的keynote
顯示又是可讀可寫。。寂寞。不知道是否是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
的方式,利用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在此~~~