count(where:)
, isMultiple(of:)
, and more.CaseIterable
protocol that automatically generates an array property of all cases in an enum.CaseIterable
protocol. At compile time, Swift will automatically generate an allCases
property that is an array of all your enum’s cases, in the order you defined them. Meta image 1 6 1000.allCases
array for it:[Pasta]
given the code above, so we could print it like this:allCases
will only take place for enums that do not use associated values. Adding those automatically wouldn’t make sense, however if you want you can add it yourself:allCases
property if any of your enum cases are marked unavailable. So, if you need allCases
then you’ll need to add it yourself, like this:CaseIterable
to the original declaration of your enum rather than an extension in order for the allCases
array to be synthesized. This means you can’t use extensions to retroactively make existing enums conform to the protocol.#warning
and #error
: the former will force Xcode to issue a warning when building your code, and the latter will issue a compile error so your code won’t build at all. Both of these are useful for different reasons:#warning
is mainly useful as a reminder to yourself or others that some work is incomplete. Xcode templates often use #warning
to mark method stubs that you should replace with your own code.#error
is mainly useful if you ship a library that requires other developers to provide some data. For example, an authentication key for a web API – you want users to include their own key, so using #error
will force them to change that code before continuing.#warning('Some message')
and #error('Some message')
. For example:#warning
and #error
work alongside the existing #if
compiler directive, and will only be triggered if the condition being evaluated is true. For example:@dynamicMemberLookup
, which instructs Swift to call a subscript method when accessing properties. This subscript method, subscript(dynamicMember:)
, is required: you’ll get passed the string name of the property that was requested, and can return any value you like.Person
struct that reads its values from a dictionary like this:@dynamicMemberLookup
attribute requires the type to implement a subscript(dynamicMember:)
method to handle the actual work of dynamic member lookup. As you can see, I’ve written one that accepts the member name as string and returns a string, and internally it just looks up the member name in a dictionary and returns its value.name
, city
, and favoriteIceCream
do not exist as properties on the Person
type. Instead, they are all looked up at runtime: that code will print “Taylor Swift” and “Nashville” for the first two calls to print()
, then an empty string for the final one because our dictionary doesn’t store anything for favoriteIceCream
.subscript(dynamicMember:)
method must return a string, which is where Swift’s type safety comes in: even though you’re dealing with dynamic data, Swift will still ensure you get back what you expected. And if you want multiple different types, just implement different subscript(dynamicMember:)
methods, like this:subscript
to return closures:user.printAddress
returns a closure that prints out a string, and the ('555 Taylor Swift Avenue')
part immediately calls it with that input. Singer
struct with a built-in name
property alongside a dynamic member subscript:name
property will be used rather than the dynamic member subscript.@dynamicMemberLookup
plays a full part in Swift’s type system, which means you can assign them to protocols, structs, enums, and classes – even classes that are marked @objc
.@dynamicMemberLookup
, and any classes that inherit from it are also automatically @dynamicMemberLookup
. So, this will print “I’m a sandwich” because HotDog
inherits from Sandwich
:@dynamicMemberLookup
by defining it on a protocol, adding a default implementation of subscript(dynamicMember:)
using a protocol extension, then making other types conform to your protocol however you want.Subscripting
protocol, provides a default subscript(dynamicMember:)
implementation that returns a message, then extends Swift’s String
to use that protocol:JSON
enum that uses dynamic member lookup to create more natural syntax for navigating through JSON:JSON
enum like this:@dynamicMemberLookup
does: it’s syntactic sugar that turns a custom subscript into simple dot syntax.Purchaseable
protocol:Array
conform to Purchaseable
if all the elements inside the array were also Purchasable
:Hashable
conformance has improved greatly in Swift 4.2. Several built-in types from the Swift standard library – including optionals, arrays, dictionaries, and ranges – now automatically conform to the Hashable
protocol when their elements conform to Hashable
. Hashable
conformance for that struct, but Swift 4.1 could not.arc4random_uniform()
and GameplayKit to get randomness, and instead rely on a cryptographically secure randomizer that’s baked right into the core of the language.random()
method on whatever numeric type you want, providing the range you want to work with. For example, this generates a random number in the range 1 through 4, inclusive on both sides:Float
, Double
, and CGFloat
:Int.random(in: 0..1) 1
, but it expresses your intent more clearly.shuffle()
and shuffled()
methods depending on whether you want in-place shuffling or not. For example:randomElement()
method to arrays, which returns one random element from the array if it isn’t empty, or nil otherwise:Hashable
protocol.Hashable
can be synthesized by the compiler. However, if you want your own hashing implementation – for example, if your type has many properties but you know that one of them was enough to identify it uniquely – you still need to write your own code using whatever algorithm you thought was best.Hasher
struct that provides a randomly seeded, universal hash function to make this process easier:combine()
repeatedly, and the order in which you add properties affects the finished hash value.Hasher
as a standalone hash generator: just provide it with whatever values you want to hash, then call finalize()
to generate the final value. For example:Hasher
uses a random seed every time it hashes an object, which means the hash value for any object is effectively guaranteed to be different between runs of your app.allSatisfy()
method that checks whether all items in a sequence pass a condition. removeAll(where:)
method that performs a high-performance, in-place filter for collections. You give it a closure condition to run, and it will strip out all objects that match the condition. filter()
like this:toggle()
method to booleans that flip them between true and false. This caused a lot of discussion in the Swift community, partly because some thought it too trivial for inclusion, but partly also because the Swift Forums discussion veered out of control at times.myVar.prop1.prop2.enabled.toggle()
avoids the potential typing errors that could be caused using manual negation.