Swift | Вопросы собесов
2.13K subscribers
28 photos
950 links
Download Telegram
🤔 Что такое дженерики?

Дженерики позволяют создавать универсальный код, который может работать с любыми типами данных, обеспечивая безопасность типов и гибкость.

Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
🤔 Пишут ли на колбеках Promis?

Да, Promises часто используются в JavaScript для управления асинхронными операциями, но они сами по себе не пишутся на колбеках. Вместо этого Promises используются как альтернатива колбекам, чтобы упростить управление асинхронным кодом и сделать его более читаемым и предсказуемым. Вот как можно использовать Promises вместо колбеков для управления асинхронным кодом:

🚩Пример с колбеками

function fetchData(callback) {
setTimeout(() => {
callback("Data received");
}, 1000);
}

fetchData((data) => {
console.log(data); // "Data received"
});


🚩Пример с Promises

function fetchData() {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve("Data received");
}, 1000);
});
}

fetchData().then((data) => {
console.log(data); // "Data received"
});


🚩Плюсы

Чистота кода
Promises помогают избежать вложенности колбеков (callback hell), делая код более линейным и читаемым.
Обработка ошибок
Promises обеспечивают единый механизм обработки ошибок с помощью .catch(), что упрощает отладку.
Цепочка вызовов
Promises поддерживают цепочки вызовов (.then()), что упрощает выполнение последовательных асинхронных операций.

🚩Асинхронные функции (async/await)

Современный синтаксис JavaScript включает async/await, который еще больше упрощает работу с асинхронным кодом на основе Promises, делая его похожим на синхронный код.
function fetchData() {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve("Data received");
}, 1000);
});
}

async function fetchDataAsync() {
try {
const data = await fetchData();
console.log(data); // "Data received"
} catch (error) {
console.error(error);
}
}

fetchDataAsync();


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🤔 Что используется для многопоточности в iOS?

Для многопоточности используются GCD (Grand Central Dispatch), OperationQueue и недавно добавленный Swift Concurrency с ключевыми словами async/await.

Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥1😁1
🤔 Как в DDD работать с зависимостями?

В Domain-Driven Design (DDD) управление зависимостями важно для создания четко разделенных и легко управляемых компонентов. Это достигается следующими методами:

🚩Методы управления зависимостями в DDD

🟠Инъекция зависимостей
Инъекция зависимостей позволяет передавать зависимости через конструкторы или сеттеры, снижая связанность и упрощая тестирование.
interface UserRepository {
findById(id: string): Promise<User | null>;
}

class UserService {
private userRepository: UserRepository;

constructor(userRepository: UserRepository) {
this.userRepository = userRepository;
}

public async getUserById(id: string): Promise<User | null> {
return await this.userRepository.findById(id);
}
}


🟠Сервисы домена
Сервисы домена содержат бизнес-логику, не принадлежащую конкретным сущностям или значимым объектам, и могут взаимодействовать с несколькими объектами или внешними сервисами.
class PaymentService {
private paymentGateway: PaymentGateway;

constructor(paymentGateway: PaymentGateway) {
this.paymentGateway = paymentGateway;
}

public async processPayment(order: Order): Promise<boolean> {
return await this.paymentGateway.charge(order.totalAmount);
}
}


🟠Анти-коррупционные слои
Анти-коррупционные слои защищают доменную модель от внешних влияний и преобразуют данные в понятные форматы.
class ExternalUserService {
public getUserData(id: string): ExternalUser {
// Получение данных от внешнего сервиса
}
}

class UserService {
private externalUserService: ExternalUserService;

constructor(externalUserService: ExternalUserService) {
this.externalUserService = externalUserService;
}

public getUser(id: string): User {
const externalUser = this.externalUserService.getUserData(id);
return new User(externalUser.id, externalUser.name, externalUser.email);
}
}


🟠Контейнеры зависимостей
Контейнеры управляют созданием и жизненным циклом зависимостей, упрощая конфигурацию и разрешение зависимостей.
import "reflect-metadata";
import { Container, injectable, inject } from "inversify";

@injectable()
class UserRepositoryImpl implements UserRepository {
public async findById(id: string): Promise<User | null> {
// Реализация метода
}
}

@injectable()
class UserService {
private userRepository: UserRepository;

constructor(@inject("UserRepository") userRepository: UserRepository) {
this.userRepository = userRepository;
}

public async getUserById(id: string): Promise<User | null> {
return await this.userRepository.findById(id);
}
}

// Конфигурация контейнера
const container = new Container();
container.bind<UserRepository>("UserRepository").to(UserRepositoryImpl);
container.bind<UserService>(UserService).toSelf();

// Разрешение зависимостей
const userService = container.get<UserService>(UserService);


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
2
🤔 Как устроен responder chain?

Responder chain — это цепочка объектов, через которую передаются события пользовательского интерфейса до тех пор, пока они не будут обработаны. Она начинается с текущего объекта и продолжается к его родителям (например, от UIView к UIViewController).

Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥1
🤔 Как интерфейс связывается с конкретной реализацией?

Связывание интерфейсов с конкретными реализациями осуществляется через инъекцию зависимостей (Dependency Injection), фабрики (Factories) и контейнеры зависимостей (Dependency Injection Containers). Эти методы абстрагируют зависимости и упрощают замену реализаций.

🚩Методы

🟠Инъекция зависимостей
Инъекция зависимостей передает зависимости через конструкторы, сеттеры или методы, обеспечивая гибкость и упрощая тестирование.
interface UserRepository {
findById(id: string): Promise<User | null>;
}

class UserRepositoryImpl implements UserRepository {
public async findById(id: string): Promise<User | null> {
return { id, name: "John Doe" };
}
}

class UserService {
private userRepository: UserRepository;

constructor(userRepository: UserRepository) {
this.userRepository = userRepository;
}

public async getUserById(id: string): Promise<User | null> {
return await this.userRepository.findById(id);
}
}

const userRepository = new UserRepositoryImpl();
const userService = new UserService(userRepository);


🟠Фабрики
Фабрики создают объекты, инкапсулируя логику создания и облегчая управление.
interface UserRepository {
findById(id: string): Promise<User | null>;
}

class UserRepositoryImpl implements UserRepository {
public async findById(id: string): Promise<User | null> {
return { id, name: "John Doe" };
}
}

class UserRepositoryFactory {
static create(): UserRepository {
return new UserRepositoryImpl();
}
}

const userRepository = UserRepositoryFactory.create();
const userService = new UserService(userRepository);


🟠Контейнеры зависимостей
Контейнеры управляют созданием и разрешением зависимостей централизованно.
import "reflect-metadata";
import { Container, injectable, inject } from "inversify";

interface UserRepository {
findById(id: string): Promise<User | null>;
}

@injectable()
class UserRepositoryImpl implements UserRepository {
public async findById(id: string): Promise<User | null> {
return { id, name: "John Doe" };
}
}

@injectable()
class UserService {
private userRepository: UserRepository;

constructor(@inject("UserRepository") userRepository: UserRepository) {
this.userRepository = userRepository;
}

public async getUserById(id: string): Promise<User | null> {
return await this.userRepository.findById(id);
}
}

const container = new Container();
container.bind<UserRepository>("UserRepository").to(UserRepositoryImpl);
container.bind<UserService>(UserService).toSelf();

const userService = container.get<UserService>(UserService);


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🤔1
🤔 Что такое Retain Cycle?

Retain Cycle — это ситуация, когда два объекта удерживают друг друга через сильные ссылки, что приводит к утечке памяти. Для предотвращения используют слабые (weak) или неявно развернутые (unowned) ссылки.

Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3😁1
🤔 Какой принцип нарушает singletone?

Singletone нарушает несколько принципов хорошего проектирования кода, особенно из набора принципов SOLID.

🚩Нарушение Принципа

🟠Единственной Ответственности (Single Responsibility Principle, SRP)
Класс должен иметь только одну причину для изменения. Singletone выполняет две задачи: управляет своим состоянием и контролирует создание своего единственного экземпляра. Это смешивание обязанностей делает класс сложнее и приводит к ситуации, когда изменение в одной из обязанностей может повлиять на другую.
class Singleton:
_instance = None

def __new__(cls, *args, **kwargs):
if not cls._instance:
cls._instance = super(Singleton, cls).__new__(cls, *args, **kwargs)
return cls._instance

def some_business_logic(self):
pass

# Здесь Singleton отвечает за управление состоянием и контролем создания экземпляра


🟠Открытости/Закрытости (Open/Closed Principle, OCP)
Классы должны быть открыты для расширения, но закрыты для модификации. Singletone трудно расширять без модификации его кода. Для изменения логики создания экземпляра или поведения необходимо изменять сам класс, что нарушает OCP.

🟠Инверсии Зависимостей (Dependency Inversion Principle, DIP)
Модули верхнего уровня не должны зависеть от модулей нижнего уровня. Оба типа модулей должны зависеть от абстракций. Singletone нарушает DIP, так как привязывает код к конкретной реализации через глобальный доступ к своему экземпляру. Это делает тестирование и замену реализации сложными, поскольку зависимость жестко закодирована.
class DatabaseConnection:
_instance = None

def __new__(cls, *args, **kwargs):
if not cls._instance:
cls._instance = super(DatabaseConnection, cls).__new__(cls, *args, **kwargs)
return cls._instance

# Любой код, использующий DatabaseConnection, теперь жестко привязан к этой реализации


🚩Проблемы с тестированием
Может создавать скрытые зависимости: Singletone часто используют глобальные состояния, которые могут усложнить тестирование. Сложность при мокировании: Из-за глобального доступа к синглтону сложно подменить его поведение в тестах.

Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
2
🤔 Что такое deadlock?

Deadlock — это ситуация, при которой два или более процесса или потока блокируют друг друга, ожидая освобождения ресурсов, которые каждый из них удерживает. Это приводит к остановке выполнения, так как никто не может продолжить работу.

Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
🤔 Где используется полиморфизм в ios разработке?

Полиморфизм широко используется в iOS разработке для создания гибкого и расширяемого кода.

🚩Протоколы (Protocols)

Протоколы в Swift позволяют определять методы и свойства, которые классы, структуры или перечисления должны реализовать. Это позволяет создавать полиморфные интерфейсы, которые могут быть реализованы различными типами.
protocol Drawable {
func draw()
}

class Circle: Drawable {
func draw() {
print("Drawing a circle")
}
}

class Square: Drawable {
func draw() {
print("Drawing a square")
}
}

func renderShape(_ shape: Drawable) {
shape.draw()
}

let shapes: [Drawable] = [Circle(), Square()]
for shape in shapes {
renderShape(shape) // Полиморфный вызов метода draw()
}


🚩Наследование (Inheritance)

Классы могут наследовать методы и свойства от родительских классов, что позволяет использовать полиморфизм через переопределение методов.
class Animal {
func makeSound() {
print("Some generic animal sound")
}
}

class Dog: Animal {
override func makeSound() {
print("Bark")
}
}

class Cat: Animal {
override func makeSound() {
print("Meow")
}
}

let animals: [Animal] = [Dog(), Cat()]
for animal in animals {
animal.makeSound() // Полиморфный вызов метода makeSound()
}


🚩Обобщения (Generics)

Обобщения позволяют писать универсальный код, который работает с любыми типами, соответствующими определенным требованиям.
func printArray<T>(items: [T]) {
for item in items {
print(item)
}
}

printArray(items: [1, 2, 3])
printArray(items: ["a", "b", "c"])


🚩Использование UIKit и SwiftUI

UIKit и SwiftUI активно используют полиморфизм. Например, UIView в UIKit и View в SwiftUI являются базовыми классами и протоколами, которые реализуют множество различных типов пользовательских интерфейсов.
let views: [UIView] = [UILabel(), UIButton(), UIImageView()]
for view in views {
// Полиморфное использование метода addSubview()
someParentView.addSubview(view)
}


🚩Dependency Injection

Полиморфизм используется в сочетании с Dependency Injection для предоставления различных реализаций интерфейсов или протоколов в зависимости от контекста.
protocol DataService {
func fetchData() -> String
}

class APIService: DataService {
func fetchData() -> String {
return "Data from API"
}
}

class MockService: DataService {
func fetchData() -> String {
return "Mock data"
}
}

class DataManager {
private var service: DataService

init(service: DataService) {
self.service = service
}

func getData() -> String {
return service.fetchData()
}
}

let apiManager = DataManager(service: APIService())
let mockManager = DataManager(service: MockService())
print(apiManager.getData()) // "Data from API"
print(mockManager.getData()) // "Mock data"


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5
🤔 Что из себя представляет структура данных stack?

Стек — это структура данных LIFO (Last In, First Out), где последний добавленный элемент извлекается первым. Операции добавления (push) и удаления (pop) выполняются только на вершине стека, что делает его удобным для управления вызовами функций и обработки данных в обратном порядке.

Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1🔥1
🤔 Как протоколы реализуют код?

Протоколы в Swift позволяют определять методы и свойства, которые классы, структуры или перечисления должны реализовать. Они обеспечивают гибкость и полиморфизм, позволяя различным типам обрабатываться одинаковым образом.

🚩Пример реализации протоколов

Определение протокола
protocol Drawable {
func draw()
}


Реализация протокола в классе
class Circle: Drawable {
func draw() {
print("Drawing a circle")
}
}

class Square: Drawable {
func draw() {
print("Drawing a square")
}
}


Использование протоколов
let shapes: [Drawable] = [Circle(), Square()]

for shape in shapes {
shape.draw()
}
// Вывод:
// Drawing a circle
// Drawing a square


🚩Расширение протоколов

Протоколы можно расширять, добавляя методы с реализацией:
extension Drawable {
func description() -> String {
return "This is a drawable object."
}
}

class Triangle: Drawable {
func draw() {
print("Drawing a triangle")
}
}

let triangle = Triangle()
print(triangle.description()) // "This is a drawable object."


🚩Протоколы и делегаты

Протоколы часто используются для делегирования:
protocol ButtonDelegate: AnyObject {
func didTapButton()
}

class Button {
weak var delegate: ButtonDelegate?

func tap() {
delegate?.didTapButton()
}
}

class ViewController: ButtonDelegate {
func didTapButton() {
print("Button was tapped")
}
}

let button = Button()
let viewController = ViewController()
button.delegate = viewController
button.tap() // "Button was tapped"


🚩Использование протоколов в iOS

UITableViewDataSource и UITableViewDelegate
class MyViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 10
}

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
cell.textLabel?.text = "Row \(indexPath.row)"
return cell
}

func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
print("Selected row \(indexPath.row)")
}
}


Custom Protocols
protocol PaymentProcessor {
func processPayment(amount: Double)
}

class PayPalProcessor: PaymentProcessor {
func processPayment(amount: Double) {
print("Processing payment of \(amount) via PayPal")
}
}

class StripeProcessor: PaymentProcessor {
func processPayment(amount: Double) {
print("Processing payment of \(amount) via Stripe")
}
}

let processors: [PaymentProcessor] = [PayPalProcessor(), StripeProcessor()]

for processor in processors {
processor.processPayment(amount: 100.0)
}


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2
🤔 Что такое модификатор памяти weak?

weak — это модификатор в Swift, используемый для предотвращения сильной ссылки на объект, чтобы избежать retain cycle. Такие ссылки автоматически обнуляются, если объект, на который они указывают, уничтожен.

Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🤔 Где использовать структуры данных?

Структуры данных используются для эффективного хранения и управления данными в различных задачах.

🚩Основные структуры данных и их применение

🟠Массивы (Arrays)
Хранение элементов одного типа с доступом по индексу. Список товаров в корзине.
let shoppingCart = ["Apple", "Banana", "Orange"]   


🟠Словари (Dictionaries)
Хранение пар ключ-значение. Информация о пользователях по ID.
var userInfo = ["userID1": "John Doe"]   


🟠Множества (Sets)
Хранение уникальных элементов. Уникальные теги постов.
var uniqueTags: Set = ["swift", "programming"]   


🟠Стек (Stack)
Управление данными в стиле LIFO. Отмена последнего действия.
struct Stack<T> {
private var elements: [T] = []
mutating func push(_ element: T) { elements.append(element) }
mutating func pop() -> T? { elements.popLast() }
}


🟠Очередь (Queue)
Управление данными в стиле FIFO. Обработка запросов.
struct Queue<T> {
private var elements: [T] = []
mutating func enqueue(_ element: T) { elements.append(element) }
mutating func dequeue() -> T? { elements.isEmpty ? nil : elements.removeFirst() }
}


🟠Связанный список (Linked List)
Эффективное добавление и удаление элементов. Управление заказами.
class Node<T> { var value: T; var next: Node?; init(value: T) { self.value = value } }   


🟠Дерево (Tree)
Иерархическая структура данных. Файловая система.
class TreeNode<T> { var value: T; var children: [TreeNode] = [] }   


🟠Граф (Graph)
Моделирование сетей и связей. Социальные сети.
class Graph { var adjList: [String: [String]] = [:] }   


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🤔 Какие бывают модификаторы доступа?

В Swift модификаторы доступа включают:
private (доступ только внутри текущего файла или типа),
fileprivate (доступ в пределах файла),
internal (доступ по умолчанию в модуле),
public (доступ в любом модуле),
open (доступ для наследования и изменения вне модуля).


Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2
🤔 Чем отличается set от dictionary?

🚩Различия между Set и Dictionary

🟠Set
Хранение уникальных элементов. Неупорядоченная коллекция. Быстрый поиск элементов.
var uniqueTags: Set = ["swift", "ios", "programming"]  


🟠Dictionary
Хранение пар ключ-значение. Неупорядоченная коллекция с ассоциативным доступом. Быстрый доступ к значениям по ключам.
var userInfo: [String: String] = ["userID1": "John Doe", "userID2": "Jane Smith"]  


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
🤔 Расскажи про capture list?

Capture list в замыканиях Swift используется для управления захватом переменных, предотвращая сильные ссылки ([weak self]) или обеспечивая их копирование ([x]). Это помогает управлять памятью и избегать утечек.

Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🤔 MVM от MVP чем отличается?

Это архитектурные паттерны, используемые в разработке программного обеспечения для разделения логики и представления данных.

🚩Основные различия между MVM и MVP

🟠MVP (Model-View-Presenter)
Компоненты
Model: Управляет данными и бизнес-логикой.
View: Отвечает за отображение данных и пользовательский интерфейс.
Presenter: Посредник между Model и View. Получает данные из Model и обновляет View.
Связь
View знает о Presenter и взаимодействует с ним.
Presenter знает о View и Model, взаимодействует с обоими.
protocol View: AnyObject {
func updateUI()
}

protocol Presenter {
func loadData()
}

class Model {
var data: String = "Hello, MVP"
}

class MyPresenter: Presenter {
private weak var view: View?
private var model: Model

init(view: View, model: Model) {
self.view = view
self.model = model
}

func loadData() {
// Получение данных из модели
view?.updateUI()
}
}

class MyViewController: UIViewController, View {
var presenter: Presenter!

override func viewDidLoad() {
super.viewDidLoad()
presenter.loadData()
}

func updateUI() {
// Обновление пользовательского интерфейса
}
}


🟠MVM (Model-View-Model)
Компоненты
Model
: Управляет данными и бизнес-логикой.
View: Отвечает за отображение данных и пользовательский интерфейс.
ViewModel: Абстракция, связывающая Model и View. Формирует данные для View и обрабатывает действия от View.
Связь
ViewModel знает о Model и может наблюдать за изменениями в ней. ViewModel предоставляет данные и команды для View. View знает только о ViewModel и не знает о Model напрямую.
class Model {
var data: String = "Hello, MVM"
}

class ViewModel {
private var model: Model

var displayData: String {
return model.data
}

init(model: Model) {
self.model = model
}

func updateModelData(newData: String) {
model.data = newData
}
}

class MyViewController: UIViewController {
var viewModel: ViewModel!

override func viewDidLoad() {
super.viewDidLoad()
// Обновление пользовательского интерфейса с использованием viewModel
print(viewModel.displayData)
}
}


🚩Основные различия

🟠Связь компонентов:
MVP: View взаимодействует с Presenter, а Presenter взаимодействует с View и Model.
MVM: View взаимодействует только с ViewModel, а ViewModel взаимодействует с Model.

🟠Зависимости
MVP: View и Presenter имеют двустороннюю зависимость, что может усложнить управление зависимостями.
MVM: ViewModel не зависит от View, что улучшает тестируемость и упрощает архитектуру.

🟠Тестируемость
MVP: Тестирование Presenter может быть сложным из-за зависимости от View.
MVM: ViewModel легко тестируется независимо от View.

🟠Применение:
MVP: Чаще используется в Android-разработке.
MVM: Популярен в iOS-разработке и при использовании SwiftUI.

Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
3👍1
🤔 Как устроено наследование в Swift?

Наследование в Swift позволяет классу (подклассу) унаследовать свойства, методы и инициализаторы от другого класса (суперкласса). Подклассы могут переопределять (override) поведение суперкласса, добавлять новые свойства и методы, но не могут наследовать структуры, перечисления или протоколы.

Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🤔 Почему надо выбрать именно эту архитектуру?

Выбор архитектурного паттерна для разработки приложения зависит от множества факторов, таких как специфика проекта, опыт команды и особенности используемой платформы.

🚩Выбор MVP (Model-View-Presenter)

🟠Четкое разделение обязанностей
MVP разделяет логику интерфейса пользователя и бизнес-логику, что делает код более модульным и управляемым.
🟠Улучшенная тестируемость
Легче тестировать Presenter отдельно от View, что улучшает покрытие тестами и упрощает отладку.
🟠Ясность в работе с View
Presenter управляет всей логикой взаимодействия с View, что делает структуру кода понятной и предсказуемой.
🟠Универсальность
MVP хорошо подходит для проектов с сложной логикой UI, где требуется много взаимодействий между пользовательским интерфейсом и бизнес-логикой.

🚩Выбор MVVM (Model-View-ViewModel)

🟠Односторонняя связь
ViewModel не знает о View, что уменьшает связанность и улучшает тестируемость.
🟠Поддержка привязок (data binding)
MVVM особенно хорошо работает с фреймворками, поддерживающими привязки данных, такими как SwiftUI или RxSwift. Это упрощает синхронизацию данных между View и ViewModel.
🟠Упрощенная логика UI
ViewModel формирует данные для View, что упрощает логику представления и делает код более чистым.
🟠Легкость в тестировании
ViewModel легко тестируется, поскольку не зависит от конкретной реализации View, что улучшает модульное тестирование.

🚩Примеры выбора архитектуры

🟠SwiftUI
Использование MVVM в SwiftUI позволяет легко управлять состоянием приложения и автоматически обновлять интерфейс при изменении данных.
🟠RxSwift
MVVM отлично сочетается с реактивным программированием, предоставляя мощные возможности для управления асинхронными операциями.
import SwiftUI

class Model {
var data: String = "Hello, MVVM"
}

class ViewModel: ObservableObject {
@Published var displayData: String = ""
private var model: Model

init(model: Model) {
self.model = model
self.displayData = model.data
}

func updateData(newData: String) {
model.data = newData
self.displayData = newData
}
}

struct ContentView: View {
@ObservedObject var viewModel: ViewModel

var body: some View {
Text(viewModel.displayData)
}
}


🟠UIKit
MVP используется для четкого разделения логики представления и бизнес-логики в сложных проектах на UIKit.
protocol View: AnyObject {
func updateUI(with data: String)
}

class Model {
var data: String = "Hello, MVP"
}

class Presenter {
private weak var view: View?
private var model: Model

init(view: View, model: Model) {
self.view = view
self.model = model
}

func loadData() {
view?.updateUI(with: model.data)
}
}

class ViewController: UIViewController, View {
private var presenter: Presenter!

override func viewDidLoad() {
super.viewDidLoad()
presenter = Presenter(view: self, model: Model())
presenter.loadData()
}

func updateUI(with data: String) {
// Обновление интерфейса
print(data)
}
}


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1