https://developer.apple.com/videos/play/wwdc2017/212/
iOS, macOS他のどのOSでも共通で使用するFoundation Frameworkの更新状況。
新しいAPIや速度等の改善、キーパス/キーバリュー監視、コード化の三つの話題。
■主な新規API
概要のみ。
□新機能
File provider communication
Improved available storage space API
Improved NSString ↔ Swift String range conversion Discrete NSProgress support in NSXPCConnection Thermal notifications on iOS
□速度向上
Copy-on-write NSArray, NSDictionary, NSSet
Data inlining
Faster calendrical calculations with lower peak memory Faster bridging of NSNumber to and from Swift
■Key Path, KeyValue Observing
□Swift3でString Key Pathsが導入された。
@objcMembers class Kid : NSObject {
dynamic var nickname: String = ""
dynamic var age: Double = 0.0
dynamic var bestFriend: Kid? = nil
dynamic var friends: [Kid] = []
}
var ben = Kid(nickname: "Benji", age: 5.5)
let kidsNameKeyPath = #keyPath(Kid.nickname)
let name = ben.valueForKeyPath(kidsNameKeyPath)
ben.setValue("Ben", forKeyPath: kidsNameKeyPath)
#keyPath(BaseType.Properties) → String
// valueForKeyPath(_: String) -> Any
// setValueForKeyPath(_, forKeyPath: String) -> Any
□それがSwift4でどう変わったか?
Proposal: SE-0161 Smart Key Paths
https://github.com/apple/swift-evolution/blob/master/proposals/0161-key-paths.md
バックスラッシュ+基底型+ドット+プロパティ名
でキーパスを生成する。
\Kid.nickname
\.nickname
\Kid.bestfriesnd?.nickname
\Data.[.startIndex]
\.[.startIndex]
struct let/var
class get/set
@objc class ストア/計算
let age = ben[KeyPath: \Kid.age]
ben[KeyPaht: \Kid.nickname] = "Ben"
String型ではなく、キーパス型となる。
AnyKeyPath
PartialKeyPath<Base>
KeyPath<Base, Property>
WritableKeyPath<Base, Property>
ReferenceWritableKeyPath<Base, Property>
appending()
\BirthdayParty.celebrant.appending(\Kid.age)
->
\BirthdayParty.celebrant.age
KeyPath<BirthdayParty, Kid>
.appending KeyPath<Kid, Double>
-> KeyPath<BirthdayParty, Double>
□Key value 監視
let observation = mia.observe(\.age) { ... }
observed = Kid, change = NSKeyValueObservedChange<Double>
let observation = mia.observe(\.age) { observed, change in
}
■Encoding and Decoding
Swiftのデータ構造をシリアライズする。プロパティ名や型の一致。
□データ構造を Codable にするだけ。
Json <--> struct
let jsonData = """
{
"name" = "Monalisa"
"email" : "...."
"date" : "2011-04-14T16:00:49Z"
}
""".data(using: .utf8)!
struct Author : Codable {
let name : String
let email: String
let date: Date
}
let decoder = JSONDecoder()
decoder.dateDecodingStrategy = .iso8601
let author = try decoder.decode(Author.self, from: jsonData)
□ネスト可能
{
"url" : "...",
"author" : {
"name" = "Monalisa"
"email" : "...."
"date" : "2011-04-14T16:00:49Z"
},
"message": "...",
"comment_count": 0
}
struct Commit : Codable {
let url: URL
struct Author : Codable {
let name : String
let email: String
let date: Date
}
let authr: Author
let message: String
let comment_count: Int
}
□Codableプロトコル
Codable
typealias Codable = Encodable & Decodable
Encodable
public protocol Encodable {
func encode(to encoder: Encoder) throws
}
Decodable
public protocol Decodable {
func init(from decoder: Decoder) throws
}
□プロパティ名や型の一致
コンパイラーが自動生成する。
struct Commit : Codable {
struct Author : Codable { ... }
let url: URL
let messge: String
let author: Author
let comment_count: Int
private enum CodingKeys : String, CodingKey {
case url
case message
case author
case comment_count
}
カスタマイズ可能
case commentCount = "comment_count"
□コードデモ 30:31〜
DecodingError.keyNotFound(let key, let context)
DecodingError.valueNotFound(let key, let context)
DecodingError.typeMissmatch(let key, let context)
OptionalにするとKeyが見つからなくてもエラーにならない。
□エラー時の対応
Error Handling
Coder Erros
Encoder
Invalid value
Decoder
Key not found
Value not found
Type Missmatch
Data corrupt
private enum CodingKeys: String, Coding Key { ... }
public init(from: decpder: Decpder) throws {
let container = try decoder.container(keyedBy: COdingKeys.self)
url = try container.decode(URL.self, forKey: .url )
guard url.scheme == "https" else {
throw DecodingError.dataCorrupted(DecodingError.Context(
codingPath: container.codingPath + [CodingKeys.yrl].
debugDescription: "URLs require https"))
}
}
□Encapsulate Endcoding details
Keyed Containers
{
Key : Value
Key : Value
Key : Value
}
Int
Unkeyd containers
[ value, value, value, value ]
Single Value Container
value
Nested Container
{
Key : Value
Key : [value, value, value]
Key : Value
}
Abstract Format from Type
Encoding Strategies