#29 Foundation’s partition(by:) is useful if we want to divide a collection into two parts and operate on both sub-collections. Example could be partitioning index paths and calling UITableView reloadRows for one part and reconfigureRows for the other part.
var indexPaths = changingIndexPaths
let reconfiguredFirstIndex = indexPaths.partition(by: canReconfigure(_:))
let reloadedIndexPaths = indexPaths[0..<reconfiguredFirstIndex] // to UITableView reloadRows
let reconfiguredIndexPaths = indexPaths[reconfiguredFirstIndex...] // to UITableView reconfigureRows
#28 When dealing with shared instances, sometimes it makes sense to introduce static subscript for skipping typing .shared everywhere.
@dynamicMemberLookup
final class DependencyContainer {
static let shared = DependencyContainer()
let database: Database
// …
}
extension DependencyContainer {
static subscript<T>(dynamicMember keyPath: KeyPath<DependencyContainer, T>) -> T {
return shared[keyPath: keyPath]
}
}
let before = DependencyContainer.shared.database
let after = DependencyContainer.database
#27 Using enums over structs for namespacing static constants. Nicer, since we can’t create an instance of AppConstants nor AppConstants.URLs.
enum AppConstants {
enum URLs {
static let api = URL(string: "https://example.com/api/data")!
// …
}
// …
}
#26 @autoclosure enables wrapping function parameters automatically with a closure, which means we can just pass a value, not a closure, to the function. Useful for custom logging functions where we might want to skip running the closure all together, depending on the build settings.
#25 Destructuring a tuple is a short way to extract values from tuples in Swift
let timestamps = (start: Date.distantPast, end: Date.distantFuture)
// Tuple destructuring
let (start, end) = timestamps
print(start, end)
// vs more verbose
let start2 = timestamps.start
let end2 = timestamps.end
print(start2, end2)
#24 In addition to functions and properties, we can add init methods to protocols in Swift. In that case, the conforming non-final class needs to use the “required” modifier. This ensures that the init is explicitly implemented by the class or its subclasses.
#23 Swift 5.9 added sleep(for:tolerance:) to the Clock protocol, which makes it simpler to add delays. Before, we needed to use an instant.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#22 If a function in Swift has multiple defer statements, then these are run in a reverse order. Something to keep in mind if the order happens to be important.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#21 We can opt in to upcoming Swift features with -enable-upcoming-feature Swift build flag. For example, in Swift 5.8 we can opt in to a new #file behaviour where it equals to the module_name/file_name instead of the full path. Useful when implementing custom logging functions.
#20 Swift 5.8 implements @backDeployed attribute for adding functionality to older API versions.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#19 When using switch for enums with associated values, and we do not want to use associated values, then we can only write out the case name .error (instead of .error(_)).
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#18 Adding custom initializer in an extension does not override the auto-generated initializer for structs in Swift.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#17 Additional concurrency checks can be enabled for async-await Swift code by adding -Xfrontend -warn-concurrency -enable-actor-data-race-checks to Other Swift Flags in Xcode
#16 Swift 5.7 introduced a new ContinuousClock API which also provides a nice way to measure time of async functions.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#15 Async property getters (but not setters) in Swift are written by adding the async keyword next to the get.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#14 Actor is a reference type which only allows one operation on their state at a time. Meaning, we can write code modifying multiple properties without worrying that these properties are read while we are still updating them.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#13 Optional pattern matching in for loop only loops over non-nil values.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#12 Swift 5.7 introduced if let shorthands. No more if let variable = variable and instead just if let variable.
#11 I have found the Foundation provided merge function for dictionaries a bit confusing to read. This is a bit shorter version I have preferred to use instead:
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#10 #unavailable() allows switching API usage based on the OS version.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#9 Swift.org has API design guidelines page. My go-to place when I am stuck with naming something.
#8Dictionary has a subscript with default value. Useful if accessing the dictionary should return a fallback value when the dictionary key is not present.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#7 Comparing boolean conditions with switch instead of if-elseif-elseif-else. Additionally, the compiler makes sure that all the possible cases are handled.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#6 Add a function with default argument values in protocol extension. In protocol extension, 'self' points at the type implementing the protocol function.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#4 Use dump() for printing out all the properties of a type. Especially useful when the type has a custom description which reveals only some information.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#3 Avoiding default in switch statements which will trigger a compiler error after adding a new case and forces reviewing all the related code.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#2 Converting integer to Data and back. Useful when working with raw bytes.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#1 Avoid optional when converting data to utf8 string with init(decoding:as:).
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters