Lately, I’ve started creating a curated list of interesting Swift articles and learnings to keep them in lazy brain memory aka Notion and being able to review it at a later point. I think this the best picks can be helpful so I’ll just share them here. I’ll go with Swift Bytes
for this series.
TLDR: For this month it’s mainly syntax related things.
1. Better map’s
map(\.{var}), filter(\.{var}), compactMap(\.{var})
Filter, map, compactMap etc can make use of KeyPath’s which makes the code much more readable and saves a bunch of characters. This is also commonly used in SwiftUI when setting the id for ForEach.
struct Task {
var name: String
var completed: Bool
var priority: Int
var isHighPriority: Bool {
priority >= 5
}
}
let tasks = [
Task(name: "Walk the dog", completed: true, priority: 5),
Task(name: "Do taxes", completed: false, priority: 2),
Task(name: "Drink some matcha", completed: true, priority: 1)
]
let completedNames = tasks
.filter(\.completed)
.filter(\.isHighPriority)
.map(\.name)
print(completedNames)
// output
// ["Walk the dog"]
2. Better Optionals
extension String? {}
There is a handy way to extend Optionals which is often worked around with the ternary operator eg like let test = task.name ?? "New Task"
or other workarounds for nil
or empty values. This can be more easily solved via extensions.
// alternative -> extension Optional where Wrapped == String
extension String? {
var isNilOrEmpty: Bool { return self == nil || self == "" }
var unwrapEmpty: String { return self ?? "" }
}
var testString: String? = nil
print(testString.isNilOrEmpty)
print(testString.unwrapEmpty)
var test2String: String? = "ocha"
print(test2String.isNilOrEmpty)
print(test2String.unwrapEmpty)
// outputs
// true
//
// false
// ocha
3. Better loops
for {var} in {list} where {condition}
Regular for
loops will normally iterate over each element whereas with the where
keyword there is an easier / cleaner way to iterate over a subset.
let numbers = [1, 2, 5, 10, 100, 200, 500, 1000]
// instead of doing this (or similar)
for num in numbers.filter({ $0 < 101 }) {
print(num)
}
// can be achieved like this
for num in numbers where (num <= 10) {
print(num)
}
// output
// 1
// 2
// 5
// 10
// 100
It’s also possible to concat conditions with &&
operator
let names = ["Swift", "Kotlin", "Golang", "Java", "Javascript"]
for name in names where (name.starts(with: "J") && (name.suffix(1) ?? "") == "a") {
print(name)
}
// output
// ["Java"]
4. Improved Keypaths
Relating to 1. Better map’s we can even improve the KeyPath’s by extending the functionality with eg an not or equal operator.
prefix func !<T>(keyPath: KeyPath<T, Bool>) -> (T) -> Bool {
return { !$0[keyPath: keyPath] }
}
let fullLengthArticles = articles.filter(!\.isActive)
func ==<T, V: Equatable>(lhs: KeyPath<T, V>, rhs: V) -> (T) -> Bool {
return { $0[keyPath: lhs] == rhs }
}
let fullLengthArticles = articles.filter(\.category == .fullLength)
- cheers & stay motivated