Irbisa · Шпаргалка
Swift: дженерики и продвинутое
Generics, opaque types, property wrappers, result builders, key paths
Что делает
Codableи как декодировать JSON, ключи которого не совпадают с именами свойств?import Foundation struct Article: Codable { let id: Int let title: String let authorName: String…Что такое generics в Swift и что может выразить
where, чего не могут угловые скобки?// Generic function: one implementation for every Comparable typefunc clamp<T: Comparable>(_ value: T, to range: ClosedRange<T>) -> T { min(max(value, range.lowerBound), range.upperBound)}print(clamp(15, to: 0...10)) // 10 (T == Int)print(clamp(0.5, to: 0...1)) // 0.5 (T == Double)…Что такое associated type, какие ограничения он накладывает на протокол и что меняют primary associated types?
protocol Store<Item> { // Item is the primary associated type associatedtype Item: Identifiable func load(id: Item.ID) async throws -> Item func save(_ item: Item) async throws}…Какая строка этого кода не компилируется и при чём здесь conditional conformance?
struct Box<Value> { let value: Value}extension Box: Equatable where Value: Equatable {} struct Token { let raw: String } print(Box(value: 1) == Box(value: 1))print([Box(value: "a")] == [Box(value: "a")])print(Box(value: Token(raw: "a")) == Box(value: Token(raw: "a")))Чем отличаются
someиanyв Swift и как они связаны с generics?protocol Shape { func area() -> Double }struct Circle: Shape { let r: Double; func area() -> Double { .pi * r * r } }struct Square: Shape { let side: Double; func area() -> Double { side * side } } // some in a return: one hidden concrete type, chosen by the functionfunc unitShape() -> some Shape { Circle(r: 1) }…Эта функция не компилируется. Почему и как это исправить?
protocol Shape { func area() -> Double }struct Circle: Shape { let r: Double; func area() -> Double { .pi * r * r } }struct Square: Shape { let side: Double; func area() -> Double { side * side } } func makeShape(rounded: Bool) -> some Shape { if rounded { return Circle(r: 1) } return Square(side: 2)}Что означает
@escapingи почему параметры-замыкания по умолчанию non-escaping?import Foundation final class ImageLoader { private var handlers: [(Data) -> Void] = [] // Called before the function returns: non-escaping, no annotation needed…Что такое key paths в Swift и где их использовать?
struct User { var name: String var age: Int} let users = [User(name: "Ada", age: 36), User(name: "Linus", age: 29)]…Как работает property wrapper и как написать свой?
@propertyWrapperstruct Clamped<Value: Comparable> { private var value: Value private let range: ClosedRange<Value> init(wrappedValue: Value, _ range: ClosedRange<Value>) {…Найдите баг:
finishedв итоге меньше числа завершённых загрузок, хотя каждое обращение к нему идёт через блокировку.@propertyWrapperfinal class Locked<Value>: @unchecked Sendable { private let lock = NSLock() private var value: Value init(wrappedValue: Value) { value = wrappedValue } var wrappedValue: Value { get { lock.withLock { value } } set { lock.withLock { value = newValue } } }} final class DownloadStats: @unchecked Sendable { @Locked var finished = 0 func markFinished() { finished += 1 } // called from many download tasks}Что такое result builder и почему
ifилиforвнутри своего билдера иногда не компилируется?struct Step { let title: String } @resultBuilderenum StepsBuilder { static func buildExpression(_ step: Step) -> [Step] { [step] } // each line static func buildBlock(_ parts: [Step]...) -> [Step] { parts.flatMap { $0 } }…Чем
Sequenceотличается отCollectionи как заставить свой тип работать в циклеfor-in?// Sequence: an iterator with a mutating next() is all for-in needsstruct Countdown: Sequence { let start: Int func makeIterator() -> Iterator { Iterator(current: start) }…Чем отличаются
#if,#availableи@availableв Swift?import Foundation#if canImport(UIKit)import UIKit // only where the SDK has UIKit#endif #if DEBUG…Как использовать Objective-C-код из Swift и Swift-код из Objective-C в одном таргете и что не может пересечь эту границу?
import Foundation // Visible to Objective-C through the generated "App-Swift.h"@objc class Logger: NSObject { @objc func log(_ message: String) { print(message) }}…Что выведет этот код и почему
mapвызывается чаще, чем можно ожидать?let numbers = [1, 2, 3, 4, 5, 6]let squares = numbers.lazy .map { n -> Int in print("map \(n)") return n * n } .filter { $0 % 2 == 0 } print("start")print(squares.first!)print(squares.first!)Что такое type erasure и когда нужен самописный type eraser, если есть
any P<T>?protocol Repository<Item> { associatedtype Item: Identifiable func fetch(id: Item.ID) async throws -> Item} struct Order: Identifiable { let id: Int }…Как Swift выполняет generic-код и почему параметр
anyможет быть медленнее generic-параметра?Что такое phantom type и от какой ошибки он защищает?
struct ID<Tag>: Hashable, Codable, Sendable { let rawValue: String} enum UserTag {} // never instantiated: exists only as a typeenum OrderTag {}…Что такое typed throws (
throws(MyError)) и когда использовать их вместо обычногоthrows?enum ParseError: Error { case empty case notANumber(String) case outOfRange(Int)}…Передача большого
Arrayв Swift выглядит бесплатной. Как работает copy-on-write и как реализовать его для своего типа?final class Storage { // final and private to the struct var pixels: [UInt8] init(pixels: [UInt8]) { self.pixels = pixels } func copy() -> Storage { Storage(pixels: pixels) }}…Найдите баг: очистка копии этого
Playlistопустошает и оригинал.struct Playlist { private final class Storage { var ids: [Int] init(ids: [Int]) { self.ids = ids } } private var storage = Storage(ids: []) var ids: [Int] { storage.ids } mutating func removeAll() { storage.ids.removeAll() } mutating func append(_ id: Int) { if !isKnownUniquelyReferenced(&storage) { storage = Storage(ids: storage.ids) } storage.ids.append(id) } mutating func insert(_ id: Int, at index: Int) { if !isKnownUniquelyReferenced(&storage) { storage = Storage(ids: storage.ids) } storage.ids.insert(id, at: index) }}Как
weakиunownedустроены в Swift изнутри (side table, три счётчика ссылок), и почему память объекта может пережить егоdeinit?final class Session { let name: String init(name: String) { self.name = name } deinit { print("deinit \(name)") }}…Нужна обёртка над сырым файловым дескриптором, которую нельзя скопировать, закрыть дважды или использовать после закрытия. Что даёт
~Copyable?import Darwin struct FileDescriptor: ~Copyable { private let fd: Int32 init?(opening path: String) {…Когда писать макрос, а не property wrapper, и почему
@Observableсделан макросом?import Foundationimport Observation @Observablefinal class CartModel { var items: [String] = []…