Table of contents

SE-0172 adds a new RangeExpression protocol and a set of prefix / postfix operators to define one-way ranges, in which either the lower or upper limit is not defined.
You can use a one-way sequence to create an infinite sequence. This is a more flexible replacement for enumerated() , if you do not want the numbering to start from scratch:
let letters = ["a","b","c","d"] let numberedLetters = zip(1..., letters) Array(numberedLetters) When a one-way sequence is used in a subscript of a collection, then startIndex or endIndex independently “fill” the missing upper or lower limit in the collection, respectively.
let numbers = [1,2,3,4,5,6,7,8,9,10] numbers[5...] // numbers[5..<numbers.endIndex] Pattern comparisons are when a one-way sequence is used in the pattern comparison construct, for example, in case or switch . Note that the compiler cannot yet determine that the switch is superfluous here .
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 introduces simple syntax for multi-line string literals ( """ ). In multi-line literals, you do not need to escape single quotes, which means that formats like JSON and HTML can be inserted into them without any escaping. The closing literal defines How many spaces will be removed from the beginning of each line.
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) To see the output of print , you can display the console by clicking ( View> Debug Area> Activate Console ).
SE-0163 is the first part of the revised string model for Swift 4. The biggest change is that now the string is a collection (as it was in Swift 1.x), that is, the String.CharacterView functionality String.CharacterView been minimized to its parent type. (Other views, UnicodeScalarView , UTF8View , and UTF16View , are still present.)
Please note that SE-0163 is not fully implemented yet, and there will be more stringent changes in the future.
let greeting = "Hello, !" // .characters greeting.count for char in greeting { print(char) } String slice instances are now a Substring type. Both String and Substring implement the StringProtocol protocol. Almost all APIs for strings live in the StringProtocol , so the String and StringProtocol mostly behave the same.
let comma = greeting.index(of: ",")! let substring = greeting[..<comma] type(of: substring) // API String Substring print(substring.uppercased()) Swift 4 will support Unicode 9, fixed problems with proper clustering of graphs for modern emoji. Everything below is now a single character:
"".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 ate all Emoji, with them look here
Character.unicodeScalarsYou can now access Character points directly without turning them into a string ( SE-0178 ).
let c: Character = "" Array(c.unicodeScalars) SE-0169 modifies the access control rules so that private announcements are now visible in extensions of the parent type in the same file. This allows you to split your type definition into several extensions and still use private access for most “private” things, reducing the need to use the fileprivate access 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 Probably one of the main features of Swift 4 is the new key path model described in SE-0161 . Unlike the string keys of the path in Cocoa, in Swift the keys of the path are strongly typed.
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]) Path keys can be specified starting from the root type and down to any combination of properties and names.
Writing the path key begins with backslash: \Book.title . Any type in Swift accepts [keyPath: …] - subscript to get or set the value for the desired path key.
sicp[keyPath: \Book.title] // sicp[keyPath: \Book.primaryAuthor.name] Path keys are a KeyPath object that can be stored and manipulated. For example, you can add additional segments to the key path to go further.
let authorKeyPath = \Book.primaryAuthor type(of: authorKeyPath) let nameKeyPath = authorKeyPath.appending(path: \.name) // sicp[keyPath: nameKeyPath] Subscript notation can also be used in path keys. Quite a convenient way to work with collections, arrays or dictionaries. This functionality is not yet implemented in the current snapshot.
//sicp[keyPath: \Book.authors[0].name] // INTERNAL ERROR: feature not implemented: non-property key path component SE-0166: Swift Archival & Serialization defines how types in Swift (classes, structures, and enums) will serialize and archive themselves. Types can make themselves (expanded) archived by implementing the Codable protocol.
In most cases, implementing the Codable protocol is all that is required. The compiler can generate the rest of the implementation itself only if all members of the type implement Codable . You can also override the standard behavior, if you need to change how it is, the type serializes itself. There are many nuances in this topic - be sure to read the proposal for further details.
// ( ) 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)] When you have a value that implements Codable , you need to pass it on to the encoder in order to archive it.
You can write your own encoders and decoders that use the infrastructure from Codable , but Swift will be supplied built-in for JSON ( JSONEncoder and JSONDecoder ) and for the property list ( PropertyListEncoder and PropertyListDecoder ). They are defined in SE-0167 . NSKeyedArchiver will also support all Codable types.
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 and Set ImprovementsSE-0165 adds several improvements for Dictionary and Set .
Creating a dictionary from a sequence of key-value pairs.
let names = ["Cagney", "Lacey", "Bensen"] let dict = Dictionary(uniqueKeysWithValues: zip(1..., names)) dict[2] Now you can determine how duplicate keys will be processed when a dictionary is created from a sequence or a sequence is merged into the current dictionary.
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 } You can define a default value for non-existing keys as a subscript argument, making the return type not optional.
dict[4, default: "(unknown)"] // This is especially important when you need to mutate a value via subscript:
let source = "how now brown cow" var frequencies: [Character: Int] = [:] for c in source { frequencies[c, default: 0] += 1 } frequencies map and filterfilter returns a Dictionary and not an Array . Similarly, the new mapValues method transforms values mapValues preserving its structure.
let filtered = dict.filter { $0.key % 2 == 0 } type(of: filtered) let mapped = dict.mapValues { value in value.uppercased() } mapped Set.filter also returns a Set and not an Array .
let set: Set = [1,2,3,4,5] let filteredSet = set.filter { $0 % 2 == 0 } type(of: filteredSet) Grouping a sequence of values into bouquets. break the words in the list by their first letter.
let contacts = ["Julia", "Susan", "John", "Alice", "Alex"] let grouped = Dictionary(grouping: contacts, by: { $0.first! }) grouped MutableCollection.swapAt methodSE-0173 introduces a new method for exchanging two items in a collection. Unlike the existing swap(_:_:) , the swapAt(_:_:) method swapAt(_:_:) accepts indices of the elements that need to be exchanged, and not the elements themselves (through inout arguments).
The reason for adding this method is that exchanging with two inout arguments is incompatible.
with the new rules of access to the memory SE-0176 . The existing swap(_:_:) function swap(_:_:) will no longer work for the exchange of two elements of the same collection.
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 reduce with inout supportSE-0171 adds a variant of the reduce method in which the result is passed as inout to the combine function. This can be a significant acceleration for algorithms that use reduce to incrementally build sequences, by eliminating copying and intermediate results.
SE-0171 not yet implemented
// 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() As represented in SE-0148 , subscript can now accept and return arguments in the form of generics.
A canonical example is the type that represents JSON data: you can define a subscript with generic so that the context of the calling code can determine the expected return type.
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"] Another example is a subscript in a Collection that takes a sequence of indices and returns an array of values of these indices.
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]] NSNumberSE-0170 corrects some dangerous behavior with a bridge between the numeric type in Swift and 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!). Now you can write the equivalent of Objective-C UIViewController <SomeProtocol> * code in Swift,
for example, declare a variable with a specific type and link it to one or several protocols simultaneously ( 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()) // Source: https://habr.com/ru/post/329580/
All Articles