Irbisa · Шпаргалка
ООП, SOLID и паттерны проектирования
ООП и SOLID в Swift, DRY, KISS и YAGNI, связность и зацепление, внедрение зависимостей, паттерны GoF, delegate, target-action, observer и coordinator, антипаттерны
Что означают DRY, KISS и YAGNI и когда устранение дублирования делает код хуже?
Что такое связанность (coupling) и связность (cohesion) и как они относятся к принципу единственной ответственности?
Как реализовать синглтон в Swift, потокобезопасен ли он и что не так с синглтонами?
@MainActorfinal class SessionStore { static let shared = SessionStore() // created lazily, exactly once, even under contention private init() {} // nobody can create a second one private(set) var token: String?…Как реализовать паттерн делегат в Swift и почему методы делегатов в Cocoa передают отправителя и используют
will,didиshould?@MainActorprotocol RatingViewDelegate: AnyObject { // AnyObject, so the reference can be weak func ratingView(_ view: RatingView, shouldSelect stars: Int) -> Bool // asks first func ratingView(_ view: RatingView, didSelect stars: Int) // reports after}…Какой принцип SOLID нарушает
CachedFeedLoaderи что происходит с вызывающей функциейfeed(from:)?protocol FeedLoader { func load(completion: @escaping (Result<[Post], Error>) -> Void) // contract: exactly once}struct CachedFeedLoader: FeedLoader { let cache: FeedCache let remote: FeedLoader func load(completion: @escaping (Result<[Post], Error>) -> Void) { completion(.success(cache.posts)) // cached posts at once remote.load(completion: completion) // then the fresh ones }}func feed(from loader: FeedLoader) async throws -> [Post] { try await withCheckedThrowingContinuation { continuation in loader.load { continuation.resume(with: $0) } }}Как выглядит принцип разделения интерфейсов в Swift и как реализации по умолчанию в протоколе могут скрыть его нарушение?
struct User { let id: String; var name: String } // before: every screen and every test double carries all of itprotocol UserService { func currentUser() async throws -> User func updateAvatar(_ jpeg: Data) async throws…Чем внедрение зависимостей отличается от инверсии зависимостей и какому модулю должен принадлежать протокол?
// Feed module: the policy owns the abstraction and names it in its own termspublic struct Post: Sendable { public let id: String public init(id: String) { self.id = id }}…Чем Factory Method отличается от Abstract Factory и где каждый из них встречается в iOS-коде?
// Factory method: UIView asks its class which layer to create, a subclass decidesfinal class GradientView: UIView { override class var layerClass: AnyClass { CAGradientLayer.self } var gradientLayer: CAGradientLayer { layer as! CAGradientLayer }}…Нужен ли в Swift паттерн Builder, если есть аргументы по умолчанию и поэлементные инициализаторы?
// Java needs a builder for optional parameters; Swift has default argumentsstruct Toast { var message: String var icon: String? = nil var duration: Duration = .seconds(2) var isDismissible = true…Чем Adapter отличается от Facade и как обернуть сторонний SDK, чтобы он не просачивался в фичи?
// The interfaces the app wants, in the app's own termsprotocol SettingsStore { func bool(forKey key: String) -> Bool func set(_ value: Bool, forKey key: String)}…Что такое паттерн Decorator в Swift, чем он отличается от расширения и наследника и чем от него отличается Proxy?
protocol ImageLoading { func image(for url: URL) async throws -> UIImage} struct RemoteImageLoader: ImageLoading { func image(for url: URL) async throws -> UIImage {…У делегата только один слушатель. Как оповещать несколько наблюдателей и при этом не держать их живыми?
@MainActor protocol PlayerObserver: AnyObject { func player(_ player: AudioPlayer, didChange state: AudioPlayer.State)} @MainActor final class AudioPlayer { enum State { case idle, playing, paused }…Что такое Chain of Responsibility и как глубоко вложенная ячейка может достучаться до своего view controller через responder chain вместо делегата?
@MainActor protocol CartActionHandling: AnyObject { func addToCart(productID: String)} extension UIResponder { // Walks up the chain (superviews, the controller, the window, the app) to the first match…Что такое паттерн Strategy, как выразить его в Swift и чем он отличается от паттерна State?
protocol ShippingPolicy { func cost(for cart: Cart) -> Decimal} struct FlatRate: ShippingPolicy { let amount: Decimal…Найдите баг: пользователь нажимает Stop, пока видео ещё буферизуется, и через мгновение оно всё равно начинает играть.
@MainActor final class PlayerModel { private(set) var isBuffering = false private(set) var isPlaying = false private let engine: PlaybackEngine init(engine: PlaybackEngine) { self.engine = engine } func playTapped(_ url: URL) { isBuffering = true; engine.load(url) } func stopTapped() { isPlaying = false; engine.pause() } // The engine calls this once enough of the video has arrived func bufferingDidFinish() { isBuffering = false isPlaying = true engine.start() }}Что такое паттерн Command и как
UndoManagerиспользует его, чтобы дать приложению отмену и повтор?struct Shape: Identifiable { let id = UUID(); var color: String } @MainActor final class Canvas { private(set) var shapes: [Shape] = [] let undoManager = UndoManager()…Что такое неправильная абстракция, как её распознать и как из неё выйти без переписывания?
// before: one row for every screen, and a flag for every new callerstruct ItemRow: View { let title: String var imageURL: URL? var price: Decimal? var isProfile = false // added for the profile screen…Какие антипаттерны вы ищете в доставшейся iOS-кодовой базе и как выбраться из god object, синглтонов повсюду и
BaseViewController?