Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4
Модуль в iOS-разработке представляет собой логически изолированную часть приложения, включающую все необходимые компоненты для выполнения определённой функции. Вот пример модуля
User с использованием архитектурного шаблона VIPER:- Modules
- User
- View
- UserView.swift
- UserViewController.swift
- Interactor
- UserInteractor.swift
- Presenter
- UserPresenter.swift
- Entity
- UserEntity.swift
- Router
- UserRouter.swift
UserView.swift
import UIKit
protocol UserViewProtocol: AnyObject {
var presenter: UserPresenterProtocol? { get set }
func showUserData(_ user: UserEntity)
}
class UserView: UIViewController, UserViewProtocol {
var presenter: UserPresenterProtocol?
override func viewDidLoad() {
super.viewDidLoad()
presenter?.viewDidLoad()
}
func showUserData(_ user: UserEntity) {
// Обновление UI с данными пользователя
}
}
UserInteractor.swift
protocol UserInteractorProtocol: AnyObject {
var presenter: UserPresenterProtocol? { get set }
func fetchUserData()
}
class UserInteractor: UserInteractorProtocol {
weak var presenter: UserPresenterProtocol?
func fetchUserData() {
let user = UserEntity(name: "John Doe", age: 30)
presenter?.didFetchUserData(user)
}
}UserPresenter.swift
protocol UserPresenterProtocol: AnyObject {
var view: UserViewProtocol? { get set }
var interactor: UserInteractorProtocol? { get set }
var router: UserRouterProtocol? { get set }
func viewDidLoad()
func didFetchUserData(_ user: UserEntity)
}
class UserPresenter: UserPresenterProtocol {
weak var view: UserViewProtocol?
var interactor: UserInteractorProtocol?
var router: UserRouterProtocol?
func viewDidLoad() {
interactor?.fetchUserData()
}
func didFetchUserData(_ user: UserEntity) {
view?.showUserData(user)
}
}UserEntity.swift
struct UserEntity {
let name: String
let age: Int
}UserRouter.swift
protocol UserRouterProtocol: AnyObject {
static func createModule() -> UIViewController
}
class UserRouter: UserRouterProtocol {
static func createModule() -> UIViewController {
let view = UserView()
let presenter: UserPresenterProtocol & UserInteractorOutputProtocol = UserPresenter()
let interactor: UserInteractorProtocol = UserInteractor()
let router: UserRouterProtocol = UserRouter()
view.presenter = presenter
presenter.view = view
presenter.interactor = interactor
presenter.router = router
interactor.presenter = presenter
return view
}
}Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3
В iOS-проектах обычно хранятся и управляются с помощью CocoaPods, популярного менеджера зависимостей для проектов на Swift и Objective-C. Вот основные моменты и шаги, связанные с хранением и управлением Pod'ами:
Установите CocoaPods, если он ещё не установлен, используя команду
sudo gem install cocoapods
Перейдите в корневую директорию вашего проекта и создайте Podfile, если он ещё не создан, используя команду
pod init
Откройте Podfile и добавьте необходимые зависимости. Например:
platform :ios, '13.0'
target 'YourApp' do
use_frameworks!
# Подключение библиотек
pod 'Alamofire', '~> 5.4'
pod 'SwiftyJSON', '~> 5.0'
end
Установите Pod'ы, используя команду
pod install
После установки Pod'ов откройте сгенерированный файл
.xcworkspace вместо .xcodeproj для работы с проектомopen YourApp.xcworkspace
Pod'ы, указанные в Podfile, загружаются и устанавливаются в директорию
Pods, которая создаётся в корневой директории вашего проекта. Также CocoaPods создаёт или обновляет несколько файлов, таких как Podfile.lock, Pods/Manifest.lock и YourApp.xcworkspace.Директория, где хранятся все установленные зависимости и их файлы.
Файл, фиксирующий версии всех установленных Pod'ов, чтобы обеспечить согласованность между разработчиками.
Файл, используемый CocoaPods для синхронизации состояния Pod'ов.
Рабочая область, которая объединяет ваш проект и его зависимости.
Добавьте
Podfile и Podfile.lock в ваш репозиторий (например, Git), чтобы обеспечить согласованность зависимостей между разработчиками. git add Podfile Podfile.lock
git commit -m "Add Podfile and Podfile.lock"
Обычно директорию
Pods/ игнорируют в системе контроля версий, добавляя её в .gitignore. Pods/
При клонировании репозитория или при изменении зависимостей выполните
pod install, чтобы установить те же версии Pod'ов, что указаны в Podfile.lock.Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
❤2👍1
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Использование наследования для расширения класса может привести к жесткой связности и сложностям в поддержке кода. Вместо наследования можно использовать следующие альтернативы: композиция, протоколы (интерфейсы), категории (extensions) и делегирование. Эти подходы предлагают большую гибкость и модульность, уменьшая вероятность проблем, связанных с наследованием.
Композиция предполагает включение объектов других классов в качестве полей и делегирование им работы. Это позволяет комбинировать различные компоненты и изменять их поведение во время выполнения.
protocol Engine {
func start()
}
class Car {
private let engine: Engine
init(engine: Engine) {
self.engine = engine
}
func start() {
engine.start()
}
}
class ElectricEngine: Engine {
func start() {
print("Electric engine starting...")
}
}
class GasolineEngine: Engine {
func start() {
print("Gasoline engine starting...")
}
}
let electricCar = Car(engine: ElectricEngine())
let gasolineCar = Car(engine: GasolineEngine())
electricCar.start() // Electric engine starting...
gasolineCar.start() // Gasoline engine starting...Протоколы определяют набор методов и свойств, которые класс или структура должны реализовать. Это позволяет создавать гибкие и переиспользуемые компоненты.
protocol Drawable {
func draw()
}
class Circle: Drawable {
func draw() {
print("Drawing a circle")
}
}
class Square: Drawable {
func draw() {
print("Drawing a square")
}
}
func render(drawable: Drawable) {
drawable.draw()
}
let shapes: [Drawable] = [Circle(), Square()]
shapes.forEach { render(drawable: $0) }Расширения позволяют добавлять новые методы и свойства к существующим классам, структурам или перечислениям без необходимости наследования или изменения исходного кода.
extension String {
func reverse() -> String {
return String(self.reversed())
}
}
let original = "hello"
let reversed = original.reverse()
print(reversed) // "olleh"Делегирование предполагает передачу ответственности за выполнение определенных задач другому объекту. Это часто используется для создания гибких и переиспользуемых компонентов.
protocol PrinterDelegate: AnyObject {
func printerDidFinishPrinting(_ printer: Printer)
}
class Printer {
weak var delegate: PrinterDelegate?
func printDocument() {
// Печать документа
print("Printing document...")
// Уведомление делегата о завершении печати
delegate?.printerDidFinishPrinting(self)
}
}
class PrintManager: PrinterDelegate {
func printerDidFinishPrinting(_ printer: Printer) {
print("Document printing completed.")
}
}
let printer = Printer()
let manager = PrintManager()
printer.delegate = manager
printer.printDocument()
// "Printing document..."
// "Document printing completed."Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👾5😁2
Это архитектурный шаблон, который разделяет логику приложения на три компонента: Model, View и Presenter. Несмотря на то, что SwiftUI тесно интегрирован с архитектурой MVVM (Model-View-ViewModel), можно адаптировать его для использования с MVP. В этом примере я покажу, как можно реализовать MVP со SwiftUI.
- Models
- User.swift
- Views
- UserView.swift
- Presenters
- UserPresenter.swift
Модель представляет данные и бизнес-логику. В нашем примере это будет простая структура
User. struct User {
let name: String
let age: Int
}Презентер управляет логикой представления и взаимодействует с моделью. Он обновляет представление в ответ на изменения данных.
protocol UserPresenterProtocol {
var user: User? { get }
func fetchUser()
}
class UserPresenter: ObservableObject, UserPresenterProtocol {
@Published var user: User?
func fetchUser() {
// Логика получения данных пользователя (например, из сети или базы данных)
self.user = User(name: "John Doe", age: 30)
}
}Представление отвечает за отображение данных и взаимодействие с пользователем. В SwiftUI представление использует
@StateObject или @ObservedObject для наблюдения за изменениями данных в презентере. import SwiftUI
struct UserView: View {
@StateObject var presenter = UserPresenter()
var body: some View {
VStack {
if let user = presenter.user {
Text("Name: \(user.name)")
Text("Age: \(user.age)")
} else {
Text("Loading...")
}
}
.onAppear {
presenter.fetchUser()
}
}
}
struct UserView_Previews: PreviewProvider {
static var previews: some View {
UserView()
}
}
User.swift
struct User {
let name: String
let age: Int
}UserPresenter.swift
protocol UserPresenterProtocol {
var user: User? { get }
func fetchUser()
}
class UserPresenter: ObservableObject, UserPresenterProtocol {
@Published var user: User?
func fetchUser() {
// Логика получения данных пользователя (например, из сети или базы данных)
self.user = User(name: "John Doe", age: 30)
}
}UserView.swift
import SwiftUI
struct UserView: View {
@StateObject var presenter = UserPresenter()
var body: some View {
VStack {
if let user = presenter.user {
Text("Name: \(user.name)")
Text("Age: \(user.age)")
} else {
Text("Loading...")
}
}
.onAppear {
presenter.fetchUser()
}
}
}
struct UserView_Previews: PreviewProvider {
static var previews: some View {
UserView()
}
}
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👀1
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥6🤯1
Synchronized в программировании используется для управления доступом к ресурсам в многопоточном окружении, чтобы предотвратить состояние гонки (race condition). В контексте iOS и Swift, Synchronized гарантирует, что только один поток может выполнять определенный блок кода в любой момент времени.В данном примере,
NSLock используется для синхронизации доступа к переменной internalState. Метод increment() увеличивает значение переменной на единицу, и блок lock/unlock гарантирует, что этот код выполнится атомарно, то есть только один поток сможет его выполнять в один момент времени. Тоже самое относится к методу getState(), который возвращает текущее значение переменной.class ThreadSafeClass {
private var internalState = 0
private let lock = NSLock()
func increment() {
lock.lock()
internalState += 1
lock.unlock()
}
func getState() -> Int {
lock.lock()
let state = internalState
lock.unlock()
return state
}
}В этом примере
DispatchQueue с атрибутом sync используется для обеспечения того, что блок кода внутри будет выполнен синхронно, то есть только один поток сможет выполнить его в данный момент времени.class ThreadSafeClass {
private var internalState = 0
private let queue = DispatchQueue(label: "com.example.threadSafeQueue")
func increment() {
queue.sync {
internalState += 1
}
}
func getState() -> Int {
return queue.sync {
internalState
}
}
}Здесь
objc_sync_enter(self) и objc_sync_exit(self) обеспечивают блокировку и разблокировку доступа к ресурсу.class ThreadSafeClass: NSObject {
private var internalState = 0
func increment() {
objc_sync_enter(self)
internalState += 1
objc_sync_exit(self)
}
func getState() -> Int {
objc_sync_enter(self)
let state = internalState
objc_sync_exit(self)
return state
}
}Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
❤1
Статические инициализаторы (`static`) выполняются один раз при загрузке класса и инициализируют статические переменные.
Нестатические инициализаторы выполняются при создании каждого экземпляра класса и используются для инициализации нестатических переменных.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥1
Использование наследования может привести к жесткой связности и сложностям в поддержке кода. Альтернативы наследованию: композиция, протоколы (интерфейсы), расширения (extensions) и делегирование. Эти подходы обеспечивают большую гибкость и модульность.
Композиция включает объекты других классов как поля и делегирует им работу, что позволяет гибко изменять поведение во время выполнения.
protocol Engine {
func start()
}
class Car {
private let engine: Engine
init(engine: Engine) {
self.engine = engine
}
func start() {
engine.start()
}
}
class ElectricEngine: Engine {
func start() {
print("Electric engine starting...")
}
}
class GasolineEngine: Engine {
func start() {
print("Gasoline engine starting...")
}
}
let electricCar = Car(engine: ElectricEngine())
let gasolineCar = Car(engine: GasolineEngine())
electricCar.start()
gasolineCar.start()Протоколы определяют набор методов и свойств, которые класс или структура должны реализовать, обеспечивая гибкость и переиспользуемость компонентов.
protocol Drawable {
func draw()
}
class Circle: Drawable {
func draw() {
print("Drawing a circle")
}
}
class Square: Drawable {
func draw() {
print("Drawing a square")
}
}
func render(drawable: Drawable) {
drawable.draw()
}
let shapes: [Drawable] = [Circle(), Square()]
shapes.forEach { render(drawable: $0) }Расширения добавляют новые методы и свойства к существующим классам, структурам или перечислениям без изменения исходного кода.
extension String {
func reverse() -> String {
return String(self.reversed())
}
}
let original = "hello"
let reversed = original.reverse()
print(reversed) // "olleh"Делегирование передает ответственность за выполнение задач другому объекту, создавая гибкие и переиспользуемые компоненты.
protocol PrinterDelegate: AnyObject {
func printerDidFinishPrinting(_ printer: Printer)
}
class Printer {
weak var delegate: PrinterDelegate?
func printDocument() {
print("Printing document...")
delegate?.printerDidFinishPrinting(self)
}
}
class PrintManager: PrinterDelegate {
func printerDidFinishPrinting(_ printer: Printer) {
print("Document printing completed.")
}
}
let printer = Printer()
let manager = PrintManager()
printer.delegate = manager
printer.printDocument()Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
❤1👍1
Reference type (ссылочный тип) хранит ссылку на область памяти, где находятся данные, и при копировании копируется только ссылка, а не сами данные. Например, объекты классов разделяют одну и ту же память.
Разница проявляется при изменении данных: value type остаётся неизменным в копиях, а reference type отражает изменения во всех ссылках.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
В объектно-ориентированном программировании классы могут выполнять различные роли в зависимости от их назначения и использования. Классы, условно названные
User и Data, могут иметь существенные различия в своей реализации и предназначении. Класс
User обычно представляет сущность пользователя в системе. Он может включать свойства и методы, специфичные для пользователя, такие как идентификатор, имя, адрес электронной почты и методы для управления этими данными.class User {
var id: Int
var name: String
var email: String
init(id: Int, name: String, email: String) {
self.id = id
self.name = name
self.email = email
}
func updateEmail(newEmail: String) {
self.email = newEmail
}
}Класс
Data чаще всего используется для представления необработанных данных или байтов. В Swift, например, Data — это структура из Foundation, которая предоставляет интерфейс для работы с бинарными данными.import Foundation
let string = "Hello, World!"
if let data = string.data(using: .utf8) {
// Преобразование строки в Data
print(data)
}
let jsonString = "{\"name\": \"John\", \"age\": 30}"
if let jsonData = jsonString.data(using: .utf8) {
// Преобразование JSON-строки в Data
do {
if let jsonObject = try JSONSerialization.jsonObject(with: jsonData, options: []) as? [String: Any] {
print(jsonObject)
}
} catch {
print("Ошибка парсинга JSON: \(error)")
}
}
User: Представляет конкретную сущность пользователя в системе. Используется для управления и хранения данных о пользователе.
Data: Представляет необработанные данные или байты. Используется для операций с бинарными данными, таких как чтение и запись файлов, сетевые операции и сериализация.
User: Обычно содержит несколько свойств, специфичных для пользователя, и методы для управления этими данными.
Data: Является универсальным контейнером для байтов, предоставляя методы для работы с этими данными.
User: Включен в бизнес-логику, тесно связан с функциональностью приложения, связанной с пользователями.
Data: Используется для низкоуровневых операций с данными, часто не связан напрямую с бизнес-логикой.
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1😁1
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚Базу Знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2
Приложения на Swift могут быть массивными из-за нескольких факторов:
Включает много функций и структур данных, что увеличивает размер бинарного файла.
Современные приложения часто используют множество внешних библиотек и фреймворков, добавляющих объем.
Компиляция для разных архитектур (например, arm64, x86_64) увеличивает размер исполняемого файла.
Большое количество изображений, видео и аудиофайлов увеличивают размер приложения.
Включение символов отладки для разработки и анализа сбоев добавляет объем.
Статические библиотеки увеличивают размер исполняемого файла по сравнению с динамическими.
Поддержка старых версий iOS требует включения дополнительных библиотек и кода.
Использование инструментов для удаления лишних архитектур из финальной сборки.
Сжатие изображений и видео, использование эффективных форматов.
Исключение символов отладки в релизной сборке.
Использование динамических библиотек для уменьшения размера основного исполняемого файла.
Удаление неиспользуемого кода и зависимостей.
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3
PO вызывает методы description или debugDescription, которые могут изменять состояние объекта.Тяжелые вычисления в методах
description или debugDescription могут замедлить отладку.Доступ к объекту в многопоточной среде может привести к состоянию гонки.
Ошибки в методах
description или debugDescription могут привести к сбоям при использовании PO.Методы, использующие блокировки, могут привести к зависанию отладчика.
Побочные эффекты
class DangerousObject {
var counter = 0
var description: String {
counter += 1 // Изменение состояния
return "Counter: \(counter)"
}
}Производительность
class HeavyObject {
var description: String {
let result = (0..<1_000_000).map { $0 * $0 }.reduce(0, +)
return "Result: \(result)"
}
}Проблемы с потоками
class ThreadUnsafeObject {
var data = [Int]()
var description: String {
return "Data count: \(data.count)"
}
}Краш приложения
class CrashObject {
var description: String {
fatalError("Should not be called")
}
}Зависания
class LockObject {
let lock = NSLock()
var description: String {
lock.lock()
defer { lock.unlock() }
return "Locked"
}
}Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Это текстовый протокол для общения в реальном времени. Он позволяет пользователям обмениваться сообщениями в каналах (чат-румах) или через личные сообщения.
Объединяют пользователей для обсуждения общих тем.
Прямой обмен сообщениями между пользователями.
Поддерживают несколько каналов и управляют соединениями пользователей.
Программы, используемые для подключения к IRC-серверам и участия в чатах.
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM