目次
- 一方向の範囲
- 行
- プライベート広告は、同じファイルの拡張子に表示されます。
- スマートウェイキー
- アーカイブとシリアル化
- 辞書とセットの改善
- MutableCollection.swapAtメソッド
- inoutサポートで削減
- 下付き文字のジェネリック
- NSNumberのブリッジ
- クラスとサブタイプのインスタンス
すべてを自宅で開始する方法は?
- サイトから最新のSwift 4スナップショットをダウンロードします
- インストーラーを実行する
- Xcode> Toolchains> Manage Toolchainsに移動し、スナップショットを選択します
一方向の範囲
SE-0172は、新しいRangeExpression
プロトコルと、下限または上限が定義されていない一方向範囲を定義するためのプレフィックス/ポストフィックス演算子のセットを追加します。
無限のシーケンス
一方向シーケンスを使用して、無限シーケンスを作成できます。 番号付けをゼロから開始したくない場合、これはenumerated()
より柔軟な代替です。
let letters = ["a","b","c","d"] let numberedLetters = zip(1..., letters) Array(numberedLetters)
コレクションの添字
コレクションの添字で一方向のシーケンスが使用される場合、 startIndex
またはendIndex
は、それぞれコレクション内の欠落している上部または下部の境界を個別に「埋める」。
let numbers = [1,2,3,4,5,6,7,8,9,10] numbers[5...] // numbers[5..<numbers.endIndex]
パターン比較
パターン比較とは、一方向シーケンスがパターン比較構造で使用されるcase
です。たとえば、 case
やswitch
です。 ここでは、コンパイラがswitch
が冗長であることをまだ判断できないことに注意してください 。
let value = 5 switch value { case 1...: print("greater than zero") case 0: print("zero") case ..<0: print("less than zero") default: fatalError("unreachable") }
行
複数行の文字列リテラル
SE-0168は、複数行の文字列リテラル( """
)の簡単な構文を導入します。複数行のリテラルでは、単一引用符をエスケープする必要がないため、JSONやHTMLなどの形式をエスケープせずに挿入できます。各行の先頭から削除されるスペースの数。
let multilineString = """ This is a multi-line string. You don't have to escape "quotes" in here. The position of the closing delimiter controls whitespace stripping. """ print(multilineString)
print
の結果を確認するには、( 表示>デバッグ領域>コンソールのアクティブ化 )をクリックしてコンソールを表示できます。
行今コレクション
SE-0163は、Swift 4の改訂された文字列モデルの最初の部分です。最大の変更点は、文字列が(Swift 1.xで使用されていたように)コレクションであるということです。 (他のビュー、 UnicodeScalarView
、 UTF8View
、およびUTF16View
がまだ存在しています。)
SE-0163はまだ完全には実装されていないことに注意してください。今後さらに厳しい変更が加えられる予定です。
let greeting = "Hello, !" // .characters greeting.count for char in greeting { print(char) }
部分文字列-ラインスライスの新しいタイプ
行スライスインスタンスは、 Substring
タイプになりました。 String
とStringProtocol
両方がStringProtocol
プロトコルを実装します。 ほとんどすべての文字列APIはStringProtocol
に存在するため、 String
とStringProtocol
基本的に同じように動作します。
let comma = greeting.index(of: ",")! let substring = greeting[..<comma] type(of: substring) // API String Substring print(substring.uppercased())
Unicode 9
Swift 4はUnicode 9をサポートし、現代の絵文字の適切な書記素クラスタリングの問題を修正します。 以下はすべて単一の文字になりました。
"".count // person + skin tone "".count // family with four members "\u{200D}\u{200D}\u{200D}".count // family + skin tones "".count // person + skin tone + profession
Habraparserはすべての絵文字を飲み込んだので 、 こちらで見てください
Character.unicodeScalars
プロパティ
これで、 Character
ポイントを文字列に変換せずに、文字ポイントに直接アクセスできます( SE-0178 )。
let c: Character = "" Array(c.unicodeScalars)
プライベート広告は、同じファイルの拡張子に表示されます。
SE-0169はアクセス制御ルールを変更して、同じファイル内の親タイプの拡張子でプライベートアナウンスが表示されるようにしました。 これにより、タイプ定義をいくつかの拡張子に分割し、ほとんどの「プライベート」なものにプライベートアクセスを使用して、 fileprivate
アクセスfileprivate
必要性を減らすことができfileprivate
。
struct SortedArray<Element: Comparable> { private var storage: [Element] = [] init(unsorted: [Element]) { storage = unsorted.sorted() } } extension SortedArray { mutating func insert(_ element: Element) { // storage storage.append(element) storage.sort() } } let array = SortedArray(unsorted: [3,1,2]) // storage __ ( fileprivate) //array.storage // error: 'storage' is inaccessible due to 'private' protection level
スマートウェイキー
おそらくSwift 4の主な機能の1つは、 SE-0161で説明されている新しいキーパスモデルです。 Cocoa文字列パスキーとは異なり、Swiftパスキーは厳密に入力されます。
struct Person { var name: String } struct Book { var title: String var authors: [Person] var primaryAuthor: Person { return authors.first! } } let abelson = Person(name: "Harold Abelson") let sussman = Person(name: "Gerald Jay Sussman") let sicp = Book(title: "Structure and Interpretation of Computer Programs", authors: [abelson, sussman])
パスキーは、ルートタイプから指定して、プロパティと名前の任意の組み合わせにドロップできます。
\Book.title
は、バックスラッシュで始まります: \Book.title
。 Swiftのすべての型は、 [keyPath: …]
- [keyPath: …]
の値を取得または設定するための添え字を受け入れます。
sicp[keyPath: \Book.title] // sicp[keyPath: \Book.primaryAuthor.name]
KeyPath
は、格納および操作できるKeyPath
オブジェクトです。 たとえば、パスキーにセグメントを追加して、さらに深くすることができます。
let authorKeyPath = \Book.primaryAuthor type(of: authorKeyPath) let nameKeyPath = authorKeyPath.appending(path: \.name) // sicp[keyPath: nameKeyPath]
パスキーの添え字
パスキーで添え字表記を使用することもできます。 コレクション、配列、または辞書を操作する非常に便利な方法。 この機能は、現在のスナップショットにはまだ実装されていません。
//sicp[keyPath: \Book.authors[0].name] // INTERNAL ERROR: feature not implemented: non-property key path component
アーカイブとシリアル化
SE-0166:Swift Archival&Serializationは、Swiftの型(クラス、構造体、および列挙)がシリアル化およびアーカイブする方法を定義します。 Codable
プロトコルを実装することにより、型は(一度)アーカイブされるようにCodable
ます。
ほとんどの場合、必要なのはCodable
プロトコルの実装だけです。 コンパイラは、型のすべてのメンバーがCodable
実装する場合にのみ、実装自体の残りを生成できます。 型のシリアル化方法を変更する必要がある場合は、標準の動作をオーバーライドすることもできます。 このトピックには多くのニュアンスがあります-詳細については、オファーを確認してください。
// ( ) Codable struct Card: Codable { enum Suit: String, Codable { case clubs, spades, hearts, diamonds } enum Rank: Int, Codable { case ace = 1, two, three, four, five, six, seven, eight, nine, ten, jack, queen, king } var suit: Suit var rank: Rank } let hand = [Card(suit: .clubs, rank: .ace), Card(suit: .hearts, rank: .queen)]
コーディング
Codable
を実装する値がある場合、アーカイブするためにエンコーダーに渡す必要があります。
Codable
のインフラストラクチャを使用する独自のエンコーダーおよびデコーダーを作成できますが、SwiftはJSON( JSONEncoder
およびJSONDecoder
)およびプロパティのリスト( PropertyListEncoder
およびPropertyListDecoder
)の組み込みを提供します。 それらはSE-0167で定義されています。 NSKeyedArchiver
は、すべてのCodable
タイプもサポートします。
import Foundation var encoder = JSONEncoder() // JSONEncoder encoder.dataEncodingStrategy encoder.dateEncodingStrategy encoder.nonConformingFloatEncodingStrategy encoder.outputFormatting encoder.userInfo let jsonData = try encoder.encode(hand) String(data: jsonData, encoding: .utf8)
デコード
let decoder = JSONDecoder() let decoded = try decoder.decode([Card].self, from: jsonData)
Dictionary
とSet
改善
SE-0165は、 Dictionary
およびSet
いくつかの機能強化を追加します。
シーケンス初期化子
キーと値のペアのシーケンスから辞書を作成します。
let names = ["Cagney", "Lacey", "Bensen"] let dict = Dictionary(uniqueKeysWithValues: zip(1..., names)) dict[2]
Merge InitializerとMergeメソッド
これで、シーケンスからディクショナリが作成されるとき、またはシーケンスが現在のディクショナリにマージされるときに、重複キーがどのように処理されるかを決定できます。
let duplicates = [("a", 1), ("b", 2), ("a", 3), ("b", 4)] let letters = Dictionary(duplicates, uniquingKeysWith: { (first, _) in first }) letters let defaults = ["foo": false, "bar": false, "baz": false] var options = ["foo": true, "bar": false] // : error: generic parameter 'S' could not be inferred // https://bugs.swift.org/browse/SR-922 //options.merge(defaults) { (old, _) in old }
デフォルト値の添え字
存在しないキーのデフォルト値を添え字の引数として定義して、戻り値のタイプをオプションにできません。
dict[4, default: "(unknown)"] //
これは、添え字を使用して値を変更する必要がある場合に特に重要です。
let source = "how now brown cow" var frequencies: [Character: Int] = [:] for c in source { frequencies[c, default: 0] += 1 } frequencies
辞書固有のmap
とfilter
filter
はArray
ではなくDictionary
を返します。 同様に、新しいmapValues
メソッドは、構造mapValues
維持しmapValues
値mapValues
変換します
let filtered = dict.filter { $0.key % 2 == 0 } type(of: filtered) let mapped = dict.mapValues { value in value.uppercased() } mapped
Set.filter
は、 Array
ではなくSet
も返します。
let set: Set = [1,2,3,4,5] let filteredSet = set.filter { $0 % 2 == 0 } type(of: filteredSet)
シーケンスのグループ化
値のシーケンスを花束にグループ化します。 リスト内の単語を最初の文字で区切ります。
let contacts = ["Julia", "Susan", "John", "Alice", "Alex"] let grouped = Dictionary(grouping: contacts, by: { $0.first! }) grouped
MutableCollection.swapAt
メソッド
SE-0173は、コレクション内の2つのアイテムを交換する新しい方法を導入しています。 既存のswap(_:_:)
とは異なり、 swapAt(_:_:)
メソッドは、( inout
引数を介して)要素自体ではなく、交換される要素のインデックスを受け入れます。
このメソッドを追加する理由は、2つのinout
引数との共有には互換性がないためです。
新しいSE-0176メモリアクセスルール。 既存のswap(_:_:)
関数swap(_:_:)
は、同じコレクションの2つの要素を交換するために機能しなくなります。
var numbers = [1,2,3,4,5] numbers.swapAt(0,1) // Will be illegal in Swift 4 (not implemented yet) swap(&numbers[3], &numbers[4]) numbers
inout
サポートでreduce
SE-0171は、結果が入力関数としてcombine
関数に渡されるreduce
メソッドオプションを追加します。 これは、 reduce
と中間結果を排除することで、 reduce
を使用してシーケンスをインクリメンタルに構築reduce
アルゴリズムの大幅な加速になります。
SE-0171はまだ実装されていません
// extension Sequence where Iterator.Element: Equatable { func uniq() -> [Iterator.Element] { return reduce(into: []) { (result: inout [Iterator.Element], element) in if result.last != element { result.append(element) } } } } [1,1,1,2,3,3,4].uniq()
下付き文字のジェネリック
SE-0148に示されているように、添え字はジェネリックの形式で引数を受け入れて返すことができるようになりました。
正規の例は、 JSON
データを表す型です。一般的な添え字を定義して、呼び出し元のコードのコンテキストが期待される戻り値の型を決定できるようにすることができます。
struct JSON { fileprivate var storage: [String:Any] init(dictionary: [String:Any]) { self.storage = dictionary } subscript<T>(key: String) -> T? { return storage[key] as? T } } let json = JSON(dictionary: [ "name": "Berlin", "country": "de", "population": 3_500_500 ]) // as? Int let population: Int? = json["population"]
別の例: Collection
添字。一連のインデックスを受け取り、これらのインデックスの値の配列を返します。
extension Collection { subscript<Indices: Sequence>(indices indices: Indices) -> [Iterator.Element] where Indices.Iterator.Element == Index { var result: [Element] = [] for index in indices { result.append(self[index]) } return result } } let words = "Lorem ipsum dolor sit amet".split(separator: " ") words[indices: [1,2]]
NSNumber
ブリッジ
SE-0170は、Swiftの数値型とNSNumber
間のブリッジに関するいくつかの危険な動作を修正します。
import Foundation let n = NSNumber(value: UInt32(543)) let v = n as? Int8 // nil in Swift 4. This would be 31 in Swift 3 (try it!).
クラスとサブタイプのインスタンス
これで、SwiftのObjective-C UIViewController <SomeProtocol> *
に同等のコードを記述できます。
たとえば、特定のタイプの変数を宣言し、1つ以上のプロトコルに同時にバインドします( SE-0156 )。 構文let variable: SomeClass & SomeProtocol1 & SomeProtocol2
import Cocoa protocol HeaderView {} class ViewController: NSViewController { let header: NSView & HeaderView init(header: NSView & HeaderView) { self.header = header super.init(nibName: nil, bundle: nil)! } required init(coder decoder: NSCoder) { fatalError("not implemented") } } // NSView // ViewController(header: NSView()) // error: argument type 'NSView' does not conform to expected type 'NSView & HeaderView' // NSView () extension NSImageView: HeaderView {} ViewController(header: NSImageView()) //