├── .gitignore ├── README.md ├── Whats-New-In-Swift-5-1.playground ├── Pages │ ├── Creating uninitialized arrays.xcplaygroundpage │ │ └── Contents.swift │ ├── Implicit returns from single-expression functions.xcplaygroundpage │ │ └── Contents.swift │ ├── Improvements to synthesized memberwise initializers.xcplaygroundpage │ │ └── Contents.swift │ ├── Introduction.xcplaygroundpage │ │ └── Contents.swift │ ├── Matching optional enums against non-optionals.xcplaygroundpage │ │ └── Contents.swift │ ├── Opaque return types.xcplaygroundpage │ │ └── Contents.swift │ ├── Ordered collection diffing.xcplaygroundpage │ │ └── Contents.swift │ ├── Static and class subscripts.xcplaygroundpage │ │ └── Contents.swift │ ├── Universal Self.xcplaygroundpage │ │ └── Contents.swift │ └── Warnings for ambiguous none cases.xcplaygroundpage │ │ └── Contents.swift └── contents.xcplayground └── playground-screenshot.png /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | # 3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 4 | 5 | ## Build generated 6 | build/ 7 | DerivedData/ 8 | 9 | ## Various settings 10 | *.pbxuser 11 | !default.pbxuser 12 | *.mode1v3 13 | !default.mode1v3 14 | *.mode2v3 15 | !default.mode2v3 16 | *.perspectivev3 17 | !default.perspectivev3 18 | xcshareddata/ 19 | xcuserdata/ 20 | 21 | ## Other 22 | .DS_Store 23 | *.moved-aside 24 | *.xccheckout 25 | *.xcscmblueprint 26 | 27 | ## Obj-C/Swift specific 28 | *.hmap 29 | *.ipa 30 | *.dSYM.zip 31 | *.dSYM 32 | 33 | ## Playgrounds 34 | timeline.xctimeline 35 | playground.xcworkspace 36 | 37 | # Swift Package Manager 38 | # 39 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies. 40 | # Packages/ 41 | # Package.pins 42 | .build/ 43 | 44 | # CocoaPods 45 | # 46 | # We recommend against adding the Pods directory to your .gitignore. However 47 | # you should judge for yourself, the pros and cons are mentioned at: 48 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 49 | # 50 | # Pods/ 51 | 52 | # Carthage 53 | # 54 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 55 | # Carthage/Checkouts 56 | 57 | Carthage/Build 58 | 59 | # fastlane 60 | # 61 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 62 | # screenshots whenever they are needed. 63 | # For more information about the recommended setup visit: 64 | # https://docs.fastlane.tools/best-practices/source-control/#source-control 65 | 66 | fastlane/report.xml 67 | fastlane/Preview.html 68 | fastlane/screenshots 69 | fastlane/test_output 70 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # What’s new in Swift 5.1? 2 | 3 | This is an Xcode playground that demonstrates the new features introduced in Swift 5.1: 4 | 5 | * Improvements to synthesized memberwise initializers 6 | * Implicit returns from single-expression functions 7 | * Universal `Self` 8 | * Opaque return types 9 | * Static and class subscripts 10 | * Warnings for ambiguous `none` cases 11 | * Matching optional enums against non-optionals 12 | * Ordered collection diffing 13 | * Creating uninitialized arrays 14 | 15 | This is designed to complement my existing article [What’s New in Swift 5.1](https://www.hackingwithswift.com/articles/182/whats-new-in-swift-5-1). You might also want to read [What’s New in Swift 5.0](https://www.hackingwithswift.com/articles/126/whats-new-in-swift-5.0) and [What’s New in Swift 4.2](https://www.hackingwithswift.com/articles/77/whats-new-in-swift-4-2). Alternatively, I have a whole website dedicated to tracking [what's new in Swift](https://www.whatsnewinswift.com) – you should check it out at . 16 | 17 | If you hit problems or have questions, you're welcome to tweet me [@twostraws](https://twitter.com/twostraws) or email . 18 | 19 | **Note:** Until a version of Xcode ships with Swift 5.1, you should [download the latest Swift trunk development snapshot](https://swift.org/download/) and activate it inside your current Xcode version. 20 | 21 | ![Screenshot of Xcode 10.2 running this playground.](playground-screenshot.png) 22 | -------------------------------------------------------------------------------- /Whats-New-In-Swift-5-1.playground/Pages/Creating uninitialized arrays.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | /*: 2 | [< Previous](@previous)           [Home](Introduction) 3 | 4 | ## Creating uninitialized arrays 5 | 6 | [SE-0245](https://github.com/apple/swift-evolution/blob/master/proposals/0245-array-uninitialized-initializer.md) introduces a new initializer for arrays that doesn’t pre-fill values with a default. This was previously available as a private API, which meant Xcode wouldn’t list it in its code completion but you could still use it if you wanted – and if you were happy to take the risk that it wouldn’t be withdrawn in the future! 7 | 8 | To use the initializer, tell it the capacity you want, then provide a closure to fill in the values however you need. Your closure will be given an unsafe mutable buffer pointer where you can write your values, as well as an `inout` second parameter that lets you report back how many values you actually used. 9 | 10 | For example, we could make an array of 10 random integers like this: 11 | */ 12 | let randomNumbers = Array(unsafeUninitializedCapacity: 10) { buffer, initializedCount in 13 | for x in 0..<10 { 14 | buffer[x] = Int.random(in: 0...10) 15 | } 16 | 17 | initializedCount = 10 18 | } 19 | /*: 20 | There are some rules here: 21 | 22 | 1. You don’t need to use all the capacity you ask for, but you can’t go *over* capacity. So, if you ask for a capacity of 10 you can set `initializedCount` to 0 through 10, but not 11. 23 | 2. If you don’t initialize elements that end up being in your array – for example if you set `initializedCount` to 5 but don’t actually provide values for elements 0 through 4 – then they are likely to be filled with random data. This is A Bad Idea. 24 | 3. If you don’t set `initializedCount` it will be 0, so any data you assigned will be lost. 25 | 26 | Now, we *could* have rewritten the above code using `map()`, like this: 27 | */ 28 | let randomNumbers2 = (0...9).map { _ in Int.random(in: 0...10) } 29 | /*: 30 | That’s certainly easier to read, but it’s less efficient: it creates a range, creates a new empty array, sizes it up to the correct amount, loops over the range, and calls the closure once for each range item. 31 | 32 |   33 | 34 | [< Previous](@previous)           [Home](Introduction) 35 | */ 36 | -------------------------------------------------------------------------------- /Whats-New-In-Swift-5-1.playground/Pages/Implicit returns from single-expression functions.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | /*: 2 | [< Previous](@previous)           [Home](Introduction)           [Next >](@next) 3 | 4 | ## Implicit returns from single-expression functions 5 | 6 | [SE-0255](https://github.com/apple/swift-evolution/blob/master/proposals/0255-omit-return.md) has removed a small but important inconsistency in the language: single-expression functions that return a value can now remove the `return` keyword and Swift will understand it implicitly. 7 | 8 | In previous versions of Swift, single-line closures that returned a value you could omit the `return` keyword because the only line of code that was there *must* be the one that returned a value. So, these two pieces of code were identical: 9 | */ 10 | let doubled1 = [1, 2, 3].map { $0 * 2 } 11 | let doubled2 = [1, 2, 3].map { return $0 * 2 } 12 | /*: 13 | In Swift 5.1, this behavior has now been extended to functions as well: if they contain a single expression – effectively a single piece of code that evaluates to a value – then you can leave off the `return` keyword, like this: 14 | */ 15 | func double(_ number: Int) -> Int { 16 | number * 2 17 | } 18 | /*: 19 | That will probably cause some people to do a double take at first, but I’m sure it will become second nature over time. 20 | 21 |   22 | 23 | [< Previous](@previous)           [Home](Introduction)           [Next >](@next) 24 | */ 25 | -------------------------------------------------------------------------------- /Whats-New-In-Swift-5-1.playground/Pages/Improvements to synthesized memberwise initializers.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | /*: 2 | [< Previous](@previous)           [Home](Introduction)           [Next >](@next) 3 | 4 | ## Improvements to synthesized memberwise initializers 5 | 6 | [SE-0242](https://github.com/apple/swift-evolution/blob/master/proposals/0242-default-values-memberwise.md) introduces major improvements to one of Swift’s most commonly used features: memberwise initializers for structs. 7 | 8 | In earlier versions of Swift, a memberwise initializer was automatically created to accept parameters matching the properties of a struct, like this: 9 | */ 10 | struct User { 11 | var name: String 12 | var loginCount: Int = 0 13 | } 14 | 15 | let piper = User(name: "Piper Chapman", loginCount: 0) 16 | /*: 17 | In Swift 5.1 this has been enhanced so that the memberwise initializer now uses default parameter values for any properties that have them. In the `User` struct we’ve given `loginCount` a default value of 0, which means we can either specify it or leave it to the memberwise initializer: 18 | */ 19 | let gloria = User(name: "Gloria Mendoza", loginCount: 0) 20 | let suzanne = User(name: "Suzanne Warren") 21 | /*: 22 | This lets us avoid repeating code, which is always welcome. 23 | 24 |   25 | 26 | [< Previous](@previous)           [Home](Introduction)           [Next >](@next) 27 | */ 28 | -------------------------------------------------------------------------------- /Whats-New-In-Swift-5-1.playground/Pages/Introduction.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | /*: 2 | # What’s new in Swift 5.1 3 | 4 | * Created by [Paul Hudson](https://twitter.com/twostraws) – [Hacking with Swift](https://www.hackingwithswift.com) 5 | * Last update: May 10th 2019 6 | 7 | This playground is designed to showcase new features introduced with Swift 5.1. I already [wrote an article on it](https://www.hackingwithswift.com/articles/182/whats-new-in-swift-5-1), but it's a lot more fun to see things in action and experiment yourself. 8 | 9 | If you hit problems or have questions, you're welcome to tweet me [@twostraws](https://twitter.com/twostraws) or email . 10 | 11 | - important: Until a version of Xcode ships with Swift 5.1, you should [download the latest Swift trunk development snapshot](https://swift.org/download/) and activate it inside your current Xcode version. 12 | 13 |   14 | 15 | ## Contents 16 | 17 | * [Improvements to synthesized memberwise initializers](Improvements%20to%20synthesized%20memberwise%20initializers) 18 | * [Implicit returns from single-expression functions](Implicit%20returns%20from%20single-expression%20functions) 19 | * [Universal Self](Universal%20Self) 20 | * [Opaque return types](Opaque%20return%20types) 21 | * [Static and class subscripts](Static%20and%20class%20subscripts) 22 | * [Warnings for ambiguous none cases](Warnings%20for%20ambiguous%20none%20cases) 23 | * [Matching optional enums against non-optionals](Matching%20optional%20enums%20against%20non-optionals) 24 | * [Ordered collection diffing](Ordered%20collection%20diffing) 25 | * [Creating uninitialized arrays](Creating%20uninitialized%20arrays) 26 | 27 |   28 | 29 | [Next >](@next) 30 | */ 31 | -------------------------------------------------------------------------------- /Whats-New-In-Swift-5-1.playground/Pages/Matching optional enums against non-optionals.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | /*: 2 | [< Previous](@previous)           [Home](Introduction)           [Next >](@next) 3 | 4 | ## Matching optional enums against non-optionals 5 | 6 | Swift has always been smart enough to handle switch/case pattern matching between optionals and non-optionals for strings and integers, but before Swift 5.1 that wasn’t extended to enums. 7 | 8 | Well, in Swift 5.1 we can now use switch/case pattern matching to match optional enums with non-optionals, like this: 9 | */ 10 | enum BuildStatus { 11 | case starting 12 | case inProgress 13 | case complete 14 | } 15 | 16 | let status: BuildStatus? = .inProgress 17 | 18 | switch status { 19 | case .inProgress: 20 | print("Build is starting…") 21 | case .complete: 22 | print("Build is complete!") 23 | default: 24 | print("Some other build status") 25 | } 26 | /*: 27 | Swift is able to compare the optional enum directly with the non-optional cases, so that code will print “Build is starting…” 28 | 29 |   30 | 31 | [< Previous](@previous)           [Home](Introduction)           [Next >](@next) 32 | */ 33 | -------------------------------------------------------------------------------- /Whats-New-In-Swift-5-1.playground/Pages/Opaque return types.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | /*: 2 | [< Previous](@previous)           [Home](Introduction)           [Next >](@next) 3 | 4 | ## Opaque return types 5 | 6 | [SE-0244](https://github.com/apple/swift-evolution/blob/master/proposals/0244-opaque-result-types.md) introduces the concept of opaque types into Swift. An opaque type is one where we’re told about the capabilities of an object without knowing specifically what kind of object it is. 7 | 8 | At first glance that sounds a lot like a protocol, but opaque return types take the concept of protocols significantly further because they are able to work with associated types, they require the same type to be used internally each time, and they allow us to hide implementation details. 9 | 10 | As an example, if we wanted to launch different kinds of fighters from a Rebel base we might write code like this: 11 | */ 12 | protocol Fighter { } 13 | struct XWing: Fighter { } 14 | 15 | func launchFighter() -> Fighter { 16 | return XWing() 17 | } 18 | 19 | let red5 = launchFighter() 20 | /*: 21 | Whoever calls that function knows it will return some sort of `Fighter` but doesn’t know precisely what. As a result, we could add `struct YWing: Fighter { }` or other types, and have any of them be returned. 22 | 23 | But there’s a problem: what if we wanted to check whether a specific fighter was Red 5? You *might* think the solution is to make `Fighter` conform to the `Equatable` protocol so we can use `==`. However, as soon as you do that Swift will throw up a particularly dreaded error for the `launchFighter` function: “Protocol 'Fighter' can only be used as a generic constraint because it has Self or associated type requirements.” 24 | 25 | The “Self” part of that error is what is hitting us here. The `Equatable` protocol has to compare two instances of itself (“Self”) to see whether they are the same, but Swift has no guarantee that the two equatable things are remotely the same – we could be comparing a Fighter with an array of integers, for example. 26 | 27 | Opaque types solve this problem because even though *we* just see a protocol being used, internally the Swift compiler knows exactly what that protocol actually resolves to – it knows it’s an `XWing`, an array of strings, or whatever. 28 | 29 | To send back an opaque type, use the keyword `some` before your protocol name: 30 | */ 31 | func launchOpaqueFighter() -> some Fighter { 32 | return XWing() 33 | } 34 | /*: 35 | From the caller’s perspective that still gets back a `Fighter`, which might be an `XWing`, a `YWing`, or something else that conforms to the `Fighter` protocol. But from the *compiler’s* perspective it knows exactly what is being returned, so it can make sure we follow all the rules correctly. 36 | 37 | For example, consider a function that returned `some Equatable` like this: 38 | */ 39 | func makeInt() -> some Equatable { 40 | Int.random(in: 1...10) 41 | } 42 | /*: 43 | When we call that, all we know is that it is some sort of `Equatable` value, however if call it twice then we can compare the results of those two calls because Swift knows for sure it will be the same underlying type: 44 | */ 45 | let int1 = makeInt() 46 | let int2 = makeInt() 47 | print(int1 == int2) 48 | /*: 49 | The same is *not* true if we had a *second* function that returned `some Equatable`, like this: 50 | */ 51 | func makeString() -> some Equatable { 52 | "Red" 53 | } 54 | /*: 55 | Even though from our perspective both send us back an `Equatable` type, and we *can* compare the results of two calls to `makeString()` or two calls to `makeInt()`, Swift won’t let us compare the return value of `makeString()` to the return value of `makeInt()` because it knows comparing a string and an integer doesn’t make any sense. 56 | 57 | An important proviso here is that functions with opaque return types must always return one specific type. If for example we tried to use `Bool.random()` to randomly launch an `XWing` or a `YWing` then Swift would refuse to build our code because the compiler can no longer tell what will be sent back. 58 | 59 | You might well think “if we always need to return the same type, why not just write the function as `func launchFighter() -> XWing`? While that might work sometimes, it creates new problems such as: 60 | 61 | - We end up with types we don’t really want to expose to the world. For example, if we used `someArray.lazy.drop { … }` we get sent back a `LazyDropWhileSequence` – a dedicated and highly specific type from the Swift standard library. All we actually care about is that this thing is a sequence; we don’t need to know how Swift’s internals work. 62 | 63 | - We lose the ability to change our mind later. Making `launchFighter()` return only an `XWing` means we can’t switch to a different type in the future, and given how much Disney relies on Star Wars toy sales that would be a problem! By returning an opaque type we can return X-Wings today, then move to B-Wings in a year – we only ever return one in any given build of our code, but we can still have the flexibility to change our mind. 64 | 65 | In some respects all this might sound similar to generics, which also solve the “Self or associated type requirements” problem. Generics allow us to write code like this: 66 | */ 67 | protocol ImperialFighter { 68 | init() 69 | } 70 | 71 | struct TIEFighter: ImperialFighter { } 72 | struct TIEAdvanced: ImperialFighter { } 73 | 74 | func launchImperialFighter() -> T { 75 | return T() 76 | } 77 | /*: 78 | That defines a new protocol that requires conforming types to be initializable with no parameters, defines two structs that conform to that protocol, then creates a generic function to use it. However, the difference here is that now *callers* of `launchImperialFighter()` are the ones to choose what kind of fighter they get, like this: 79 | */ 80 | let fighter1: TIEFighter = launchImperialFighter() 81 | let fighter2: TIEAdvanced = launchImperialFighter() 82 | /*: 83 | If you *want* callers to be able to select their data type then generics work well, but if you want the *function* to decide the return type then they fall down; 84 | 85 | So, opaque result types allow us to do several things: 86 | 87 | - Our functions decide what type of data gets returned, not the caller of those functions. 88 | - We don’t need to worry about Self or associated type requirements, because the compiler knows exactly what type is inside. 89 | - We get to change our minds in the future whenever we need to. 90 | - We don’t expose private internal types to the outside world. 91 | 92 |   93 | 94 | [< Previous](@previous)           [Home](Introduction)           [Next >](@next) 95 | */ 96 | -------------------------------------------------------------------------------- /Whats-New-In-Swift-5-1.playground/Pages/Ordered collection diffing.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | /*: 2 | [< Previous](@previous)           [Home](Introduction)           [Next >](@next) 3 | 4 | ## Ordered collection diffing 5 | 6 | [SE-0240](https://github.com/apple/swift-evolution/blob/master/proposals/0240-ordered-collection-diffing.md) introduces the ability to calculate and apply the differences between ordered collections. This could prove particularly interesting for developers who have complex collections in table views, where they want to add and remove lots of items smoothly using animations. 7 | 8 | The basic principle is straightforward: Swift 5.1 gives us a new `difference(from:)` method that calculates the differences between two ordered collections – what items to remove and what items to insert. This can be used with any ordered collection that contains `Equatable` elements. 9 | 10 | To demonstrate this, we can create an array of scores, calculate the difference from one to the other, then loop over those differences and apply each one to make our two collections the same. 11 | 12 | **Note:** Because Swift now ships inside Apple’s operating systems, new features like this one must be used with an `#available` check to make sure the code is being run on an OS that includes the new functionality. For features that will land in an unknown, unannounced operating system shipping at some point in the future, a special version number of “9999” is used to mean “we don’t know what the actual number is just yet.” 13 | 14 | Here’s the code: 15 | */ 16 | var scores1 = [100, 91, 95, 98, 100] 17 | let scores2 = [100, 98, 95, 91, 100] 18 | 19 | if #available(iOS 9999, *) { 20 | let diff = scores2.difference(from: scores1) 21 | 22 | for change in diff { 23 | switch change { 24 | case .remove(let offset, _, _): 25 | scores1.remove(at: offset) 26 | case .insert(let offset, let element, _): 27 | scores1.insert(element, at: offset) 28 | } 29 | } 30 | 31 | print(scores1) 32 | } 33 | /*: 34 | For more advanced animations, you can use the third value of the changes: `associatedWith`. So, rather than using `.insert(let offset, let element, _)` above you might write `.insert(let offset, let element, let associatedWith)` instead. This lets you track pairs of changes at the same time: moving an item two places down in your collection is a removal then an insertion, but the `associatedWith` value ties those two changes together so you treat it as a move instead. 35 | 36 | Rather than applying changes by hand, you can apply the whole collection using a new `applying()` method, like this: 37 | */ 38 | if #available(iOS 9999, *) { 39 | let diff = scores2.difference(from: scores1) 40 | let result = scores1.applying(diff) ?? [] 41 | } 42 | /*: 43 |   44 | 45 | [< Previous](@previous)           [Home](Introduction)           [Next >](@next) 46 | */ 47 | -------------------------------------------------------------------------------- /Whats-New-In-Swift-5-1.playground/Pages/Static and class subscripts.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | /*: 2 | [< Previous](@previous)           [Home](Introduction)           [Next >](@next) 3 | 4 | ## Static and class subscripts 5 | 6 | [SE-0254](https://github.com/apple/swift-evolution/blob/master/proposals/0254-static-subscripts.md) adds the ability to mark subscripts as being *static*, which means they apply to types rather than instances of a type. 7 | 8 | Static properties and methods are used when one set of values is shared between all instances of that type. For example, if you had one centralized type to store your app settings, you might write code like this: 9 | */ 10 | public enum OldSettings { 11 | private static var values = [String: String]() 12 | 13 | static func get(_ name: String) -> String? { 14 | return values[name] 15 | } 16 | 17 | static func set(_ name: String, to newValue: String?) { 18 | print("Adjusting \(name) to \(newValue ?? "nil")") 19 | values[name] = newValue 20 | } 21 | } 22 | 23 | OldSettings.set("Captain", to: "Gary") 24 | OldSettings.set("Friend", to: "Mooncake") 25 | print(OldSettings.get("Captain") ?? "Unknown") 26 | /*: 27 | Wrapping the dictionary inside a type means that we can control access more carefully, and using an enum with no cases means we can’t try to instantiate the type – we can’t make various instances of `Settings`. 28 | 29 | With Swift 5.1 we can now use a static subscript instead, allowing us to rewrite our code to this: 30 | */ 31 | public enum NewSettings { 32 | private static var values = [String: String]() 33 | 34 | public static subscript(_ name: String) -> String? { 35 | get { 36 | return values[name] 37 | } 38 | set { 39 | print("Adjusting \(name) to \(newValue ?? "nil")") 40 | values[name] = newValue 41 | } 42 | } 43 | } 44 | 45 | NewSettings["Captain"] = "Gary" 46 | NewSettings["Friend"] = "Mooncake" 47 | print(NewSettings["Captain"] ?? "Unknown") 48 | /*: 49 | Custom subscripts like this have always been possible for instances of types; this improvement makes static or class subscripts possible too. 50 | 51 |   52 | 53 | [< Previous](@previous)           [Home](Introduction)           [Next >](@next) 54 | */ 55 | -------------------------------------------------------------------------------- /Whats-New-In-Swift-5-1.playground/Pages/Universal Self.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | /*: 2 | [< Previous](@previous)           [Home](Introduction)           [Next >](@next) 3 | 4 | ## Universal `Self` 5 | 6 | [SE-0068](https://github.com/apple/swift-evolution/blob/master/proposals/0068-universal-self.md) expands Swift’s use of `Self` so that it refers to the containing type when used inside classes, structs, and enums. This is particularly useful for *dynamic* types, where the exact type of something needs to be determined at runtime. 7 | 8 | As an example, consider this code: 9 | */ 10 | class NetworkManager { 11 | class var maximumActiveRequests: Int { 12 | return 4 13 | } 14 | 15 | func printDebugData() { 16 | print("Maximum network requests: \(NetworkManager.maximumActiveRequests).") 17 | } 18 | } 19 | /*: 20 | That declares a static `maximumActiveRequests` property for a network manager, and adds a `printDebugData()` method to print the static property. That works fine right now, but when `NetworkManager` is subclassed things become more complicated: 21 | */ 22 | class ThrottledNetworkManager: NetworkManager { 23 | override class var maximumActiveRequests: Int { 24 | return 1 25 | } 26 | } 27 | /*: 28 | That subclass changes `maximumActiveRequests` so that it allows only one request at a time, but if we call `printDebugData()` it will print out the value from its parent class: 29 | */ 30 | let manager = ThrottledNetworkManager() 31 | manager.printDebugData() 32 | /*: 33 | That *should* print out 1 rather than 4, and that’s where SE-0068 comes in: we can now write `Self` (with a capital S) to refer to the current type. So, we can rewrite `printDebugData()` to this: 34 | */ 35 | class ImprovedNetworkManager { 36 | class var maximumActiveRequests: Int { 37 | return 4 38 | } 39 | 40 | func printDebugData() { 41 | print("Maximum network requests: \(Self.maximumActiveRequests).") 42 | } 43 | } 44 | /*: 45 | This means `Self` works the same way as it did for protocols in earlier Swift versions. 46 | 47 |   48 | 49 | [< Previous](@previous)           [Home](Introduction)           [Next >](@next) 50 | */ 51 | -------------------------------------------------------------------------------- /Whats-New-In-Swift-5-1.playground/Pages/Warnings for ambiguous none cases.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | /*: 2 | [< Previous](@previous)           [Home](Introduction)           [Next >](@next) 3 | 4 | ## Warnings for ambiguous `none` cases 5 | 6 | Swift’s optionals are implemented as an enum of two cases: `some` and `none`. This gave rise to the possibility of confusion if we created our own enums that had a `none` case, then wrapped that inside an optional. 7 | 8 | For example: 9 | */ 10 | enum BorderStyle { 11 | case none 12 | case solid(thickness: Int) 13 | } 14 | /*: 15 | Used as a non-optional this was always clear: 16 | */ 17 | let border1: BorderStyle = .none 18 | print(border1) 19 | /*: 20 | That will print “none”. But if we used an optional for that enum – if we didn’t know what border style to use – then we’d hit problems: 21 | */ 22 | let border2: BorderStyle? = .none 23 | print(border2) 24 | /*: 25 | That prints “nil”, because Swift assumes `.none` means the optional is empty, rather than an optional with the value `BorderStyle.none`. 26 | 27 | In Swift 5.1 this confusion now prints a warning: “Assuming you mean 'Optional.none'; did you mean 'BorderStyle.none' instead?” This avoids the source compatibility breakage of an error, but at least informs developers that their code might not quite mean what they thought. 28 | 29 |   30 | 31 | [< Previous](@previous)           [Home](Introduction)           [Next >](@next) 32 | */ 33 | -------------------------------------------------------------------------------- /Whats-New-In-Swift-5-1.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /playground-screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/twostraws/whats-new-in-swift-5-1/1613e03aa36412b029d664a2a6e4cb3594ac87bf/playground-screenshot.png --------------------------------------------------------------------------------