Библиотека мобильного разработчика | Android, iOS, Swift, Retrofit, Moshi, Chuck
9.62K subscribers
1.64K photos
80 videos
52 files
4.44K links
Все самое полезное для мобильного разработчика в одном канале.

По рекламе: @proglib_adv

Учиться у нас: https://proglib.io/w/b60af5a4

Для обратной связи: @proglibrary_feeedback_bot

РКН: https://gosuslugi.ru/snet/67a4adec1b17b35b6c0d8389
Download Telegram
📱 Осваиваем скроллинг в SwiftUI

Начиная с iOS 17 в SwiftUI появилась функция scrollTargetBehavior, позволяющая разработчикам управлять поведением прокрутки с большей точностью. Будь то выравнивание представлений или реализация пользовательских эффектов пагинации, ScrollTargetBehavior обеспечивает надежную поддержку. Что еще более важно, разработчики могут создавать собственные реализации функции для удовлетворения конкретных потребностей.

В этой статье на реальном примере автор показывает, как использовать scrollTargetBehavior и в конечном итоге реализовать пользовательскую логику управления прокруткой.

👉 Читать статью

#новость #ios #swift
🥰41
🍏 Назовите 5 утверждений передачи управления (Control Transfer Statements)

Вот они слева-направо (сверху-вниз):

Break

Continue

Fallthrough

Throw

Return

Операторы передачи управления изменяют порядок выполнения вашего кода.

Например, вы можете использовать оператор передачи управления break для завершения выполнения цикла for, когда продолжение цикла считается ненужным:

for choice in choices:if isCorrect(choice):print(«Correct choice found!»)break


#swift
2
😴 Task.sleep() и Task.yield()

В Swift Concurrency мы можем использовать Task.sleep() и Task.yield(), чтобы перевести конкретную задачу в режим ожидания или приостановки в течение определённого периода времени. Оба они выглядят и ведут себя одинаково, но есть несколько существенных различий, о которых следует знать Swift-разработчикам.

Зная эти различия, вы сможете лучше понять, когда и как использовать те или иные функции, а также оптимизировать свой код соответствующим образом. Прежде чем перейти к рассмотрению различий, автор сначала объясняет, что делают эти модификаторы.

👉 Читать статью

#новость #swift
🤩31👍1
Можно ли в Swift вернуть из функции несколько значений

Как и большинство языков программирования, Swift позволяет каждой функции возвращать только одно значение. Если этот элемент является примитивным типом, вы вернёте только одно значение.

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

➡️ Вот как можно вернуть несколько значений, хранящихся в кортеже:

func functionWithMultipleReturnValues(
val1: Int,
val2: Int
) -> (sum: Int, product: Int) {
let sum = val1 + val2
let prod = val1 * val2
return (sum, prod)
}
let result = functionWithMultipleReturnValues(val1: 10, val2: 20)
let s = result.sum
let p = result.product


🐸 Библиотека мобильного разработчика

#буст #MiddlePath #Swift
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3
Для чего используется Guard

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

Например, оператор guard используется для выхода из функции:

func myFun() {
guard false else {
print("This block is run")
return
}
print("This is never run")
}

myFun()


Вывод:

This block is run


👉 Узнайте больше о ключевом слове guard, прочитав эту статью

🐸 Библиотека мобильного разработчика

#буст #JuniorKit #Swift
Please open Telegram to view this post
VIEW IN TELEGRAM
2
💡 Горячие клавиши для рефакторинга в AppCode

AppCode — мощная IDE от JetBrains для iOS-разработки, и если ты хочешь писать код быстрее и чище — эти хоткеи must have.

1️⃣ Переименование (Rename)

Shift + F6

Переименовывает переменные, классы, методы — и IDE сама обновит все упоминания.

2️⃣ Извлечение переменной (Extract Variable)

Ctrl + Alt + V (Cmd + Option + V на Mac)

Выделяешь выражение → IDE создаёт переменную автоматически.

3️⃣ Извлечение метода (Extract Method)

Ctrl + Alt + M (Cmd + Option + M)

Отлично помогает разгрести длинные функции и вынести повторяющийся код.

4️⃣ Инлайн (Inline)

Ctrl + Alt + N (Cmd + Option + N)

Обратно «встраивает» метод или переменную прямо в место вызова.

5️⃣ Безопасное удаление (Safe Delete)

Alt + Delete (Cmd + Delete)

Проверит, где элемент используется, и безопасно удалит его без сюрпризов.

🐸 Библиотека мобильного разработчика

#буст #MiddlePath #Swift
Please open Telegram to view this post
VIEW IN TELEGRAM
4
Что такое дженерики

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

Представьте, что вы пишете трехмерную векторную структуру, но хотите иметь возможность создавать векторы, используя целые, плавающие и двойные числа. Вы определенно не хотите писать один и тот же код для каждого типа данных отдельно.

Именно здесь вы можете использовать дженерики.

Например, вы можете создать общий тип для параметров (для представления любого типа), используя букву, например T, следующим образом:

struct Vec3D<T> {
let x, y, z: T
init(x: T, y: T, z: T) {
self.x = x
self.y = y
self.z = z
}
}
let intVector = Vec3D(x: 1, y: 2, z: 5)
let floatVector = Vec3D(x: 1.0, y: 2.0, z: 5.0)


🐸 Библиотека мобильного разработчика

#буст #JuniorKit #Swift
Please open Telegram to view this post
VIEW IN TELEGRAM
1
Предложите небольшую доработку для следующего кода

if age >= 18 {
driveCar()
} else {
doNotDrive()
}


Этот код хорошо работает - но можете ли вы предложить небольшое улучшение рефакторинга, чтобы сделать его еще лучше?

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

age >= 18 ? driveCar() : doNotDrive()


🐸 Библиотека мобильного разработчика

#буст #JuniorKit #Swift
Please open Telegram to view this post
VIEW IN TELEGRAM
🥱62😢2🤔1
🎮 «Чистая» структура View-компонентов в SwiftUI

В проектах на SwiftUI тело View может быстро разрастись: десятки вложенных VStack/HStack, логика отображения, стили — всё в одном месте.

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

1️⃣ Извлечение отдельных View

Если часть интерфейса имеет собственное назначение — вынеси её в отдельный struct-View:

struct ArticleRow: View {
let article: Article
var body: some View {
HStack { … }
}
}


Затем:

ForEach(articles, id: \.url) { article in
ArticleRow(article: article)
}


Это делает главный View более “обзорным” и облегчает повторное использование.


2️⃣ Использование ViewModifiers для стилей

Когда видишь дублирования стилей, вынеси их:

struct CardStyle: ViewModifier {
func body(content: Content) -> some View {
content
.padding()
.background(Color(.secondarySystemBackground))
.cornerRadius(8)
}
}
extension View {
func cardStyle() -> some View {
modifier(CardStyle())
}
}


Теперь:

ArticleRow(article: article)
.cardStyle()


Так ты централизуешь “язык дизайна” и можешь менять стиль в одном месте.

3️⃣ Создание универсальных расширений для просмотра

Если повторяются шаблоны (например, “заголовок секции”), можно сделать расширение:

extension View {
func sectionHeader(_ title: String) -> some View {
VStack(alignment: .leading, spacing: 4) {
Text(title)
.font(.title3)
.bold()
self
}
}
}


Пример:

VStack {
ForEach(articles, id: \.url) { article in
ArticleRow(article: article)
}
}
.sectionHeader("Articles")


Такие расширения уменьшают вложенность и делают код декларативнее.

📌 Практическое руководство по созданию хорошей архитектуры SwiftUI

Если вы не уверены, стоит ли что-то извлекать, спросите:

Есть ли у этого элемента пользовательского интерфейса чёткое назначение и возможность повторного использования?


🔘 Если да → создайте новый View или ViewModifier.

🔘 Если нет → оставьте его локальным или используйте вычисляемое свойство.

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

🐸 Библиотека мобильного разработчика

#АрхитектурныйКод #SeniorView #Swift
Please open Telegram to view this post
VIEW IN TELEGRAM
3🤝1
Что такое полиморфизм

Полиморфизм представлять возможность взаимозаменяемости типов, которые находятся в одной иерархии классов. Например, возьмем следующую иерархию классов:

class Person{
var name: String
var age: Int

init(name: String, age: Int){
self.name = name
self.age = age
}
func display(){
print("Имя: \(name) Возраст: \(age)")
}
}

class Employee : Person{
var company: String
init(name: String, age: Int, company: String) {
self.company = company
super.init(name:name, age: age)
}
override func display(){
print("Имя: \(name) Возраст: \(age) Сотрудник компании: \(company)")
}
}

class Manager : Employee{
override func display(){
print("Имя: \(name) Возраст: \(age) Менеджер компании: \(company)")
}
}


В данном случае класс Manager (менеджер компании) наследуется от класса Employee (сотрудник компании), а класс Employee - от класса Person (человек). Тем самым класс Manager ненапрямую тоже наследуется от Person.

Поскольку и сотрудник компании и менеджер компании в то же время являются людьми, то есть объектами класса Person, то мы можем написать следующим образом:

let tom: Person = Person(name:"Tom", age: 23)
let bob: Person = Employee(name: "Bob", age: 28, company: "Apple")
let alice: Person = Manager(name: "Alice", age: 31, company: "Microsoft")


Все три константы представляют тип Person, однако первая хранит ссылку на объект Person, вторая - на объект Employee, а третья - на объект Manager. Таким образом, переменная или константа одного типа может принимать многообразные формы в зависимости от конкретного объекта, на который она указывает.

Но что будет, если мы вызовем метод display() для всех трех объектов:

let tom: Person = Person(name:"Tom", age: 23)
let bob: Person = Employee(name: "Bob", age: 28, company: "Apple")
let alice: Person = Manager(name: "Alice", age: 31, company: "Microsoft")

tom.display() // Имя: Tom Возраст: 23
bob.display() // Имя: Bob Возраст: 28 Сотрудник компании: Apple
alice.display() // Имя: Alice Возраст: 31 Менеджер компании: Microsoft


Несмотря на то, что все три константы представляют тип Person, при вызове метода display будет вызываться реализация метода именно того класса, ссылку на объект которого хранит константа. Данный примем называется динамической диспетчеризацией - во время выполнения программы на основании типа объекта система решает, какую именно реализацию метода вызывать.

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

🐸 Библиотека мобильного разработчика

#буст #JuniorKit #Swift
Please open Telegram to view this post
VIEW IN TELEGRAM
5🥱1
🔍 Архитектура Clean Swift

В Clean Swift приложение состоит из сцен, т.е. каждый экран приложения — это одна сцена. Основное взаимодействие в сцене идет через последовательный цикл между компонентами ViewController -> Interactor -> Presenter. Это называется VIP цикл.

Мостом между компонентами выступает файл Models, который хранит в себе передаваемые данные. Так же есть Router, отвечающий за переход и передачу данных между сценами, и Worker, который берет часть логики Interactor’a на себя.

🔹 View

Storyboard’ы, XIB’ы или UI элементы, написанные через код.

🔹 ViewController

Отвечает только за конфигурацию и взаимодействие с View. В контроллере не должно находиться никакой бизнес логики, взаимодействия с сетью, вычислений и так далее.
Его задача обрабатывать события с View, отображать или отправлять данные (без обработки и проверок) в Interactor.

🔹 Interactor

Содержит в себе бизнес логику сцены.

Он работает с сетью, базой данных и модулями устройства.

Interactor получает запрос из ViewController’a (с данными или пустой), обрабатывает его и, если это требуется, передает новые данные в Presenter.

🔹 Presenter

Занимается подготовкой данных для отображения.

Как пример, добавить маску на номер телефона или сделать первую букву в названии заглавной.
Обрабатывает данные, получение из Interactor’a, после чего отправляет их обратно во ViewController.

🔹 Models

Набор структур для передачи данных между компонентами VIP цикла. Каждый круг цикла имеет в себе 3 вида структур:

🔘 Request — Структура с данными (текст из TextField и т.д.) для передачи из ViewController'a в Interactor
🔘 Response — Структура с данными (загруженными из сети и т.д.) для передачи из Interactor в Presenter
🔘 ViewModel — Структура с обработанными данными (форматирование текста и т.д.) в Presenter’e для передачи обратно во ViewController

🔹 Worker

Разгружает Interactor, забирая на себя часть бизнес логики приложения, если Interactor стремительно разрастается.

Так же можно создавать общие для всех сцен Worker’ы, если их функционал используется в нескольких сценах.

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

🔹 Router

В Router выносится вся логика, отвечающая за переходы и передачу данных между сценами.

____________________

Для прояснения картины работы VIP цикла приведу стандартный пример — авторизация.

1. Пользователь ввел свой логин и пароль, нажал на кнопку авторизации

2. У ViewController срабатывает IBAction, после чего создается структура с введенными, в TextField’ы, данными пользователя (Models -> Request)

3. Созданная структура передается в метод fetchUser в Interactor’e

4. Interactor отправляет запрос в сеть и получает ответ об успешности авторизации

5. На основе полученных данных, создает структуру с результатом (Models -> Response) и передается в метод presentUser в Presenter’e

6. Presenter форматирует данные по необходимости и возвращает их (Models -> ViewModel) в метод displayUser в ViewController’e

7. ViewController отображает полученные данные пользователю. В случае с авторизацией, может выводиться ошибка или срабатывать переход на другую сцену с помощью Router

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

🐸 Библиотека мобильного разработчика

#АрхитектурныйКод #SeniorView #Swift
Please open Telegram to view this post
VIEW IN TELEGRAM
3