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

Список каналов: https://t.me/proglibrary/9197
Учиться у нас: https://proglib.io/w/330353e8

Обратная связь: @proglibrary_feedback_bot

По рекламе: @proglib_adv
Прайс: @proglib_advertising
Download Telegram
Вопрос по Flutter
#вопросы_с_собеседований

Какие режимы сборки доступны во Flutter?
...............................................................................................................

Режим отладки - предназначен для отладки приложений на устройстве или симуляторе.
Profile Mode - доступны некоторые возможности отладки, а также анализ производительности приложения в тестовых раундах.
Режим выпуска - используется при развертывании приложения и обеспечивает более высокую производительность. В этом режиме нельзя отлаживать или редактировать код.
Вопрос по Kotlin
#вопросы_с_собеседований

Что такое reified?
...............................................................................................................

reified — это ключевое слово, которое может быть использовано только в inline-функциях. reified позволяет получить информацию о типе generic-параметра во время выполнения программы. В обычном случае, информация о типах стирается и недоступна во время выполнения, но с помощью reified можно сохранять эту информацию и использовать в других частях приложения.
Вопрос по Swift
#вопросы_с_собеседований

Как можно кастомизировать view transitions в Swift UI?
...............................................................................................................

Можно использовать модификатор .transition(), чтобы настроить переход между двумя вьюхами. Можно указать тип перехода, например .slide, .move или .scale, и направление перехода, например .leading, .trailing, .top или .bottom.
#вопросы_с_собеседований

Как работают SAM-conversions?

Single Abstract Method (SAM) интерфейсы — это интерфейсы только с одним абстрактным методом (функциональные интерфейсы). Kotlin поддерживает соглашение SAM — автоматическую конвертацию функций и lambda между Kotlin и Java.

SAM-conversions позволяют использовать Java-интерфейсы с единственным абстрактным методом в Kotlin, как если бы это были функциональные типы. В Kotlin вы можете использовать такие интерфейсы для создания лямбда-выражений без явного определения функционального типа.

При использовании интерфейса с единственным абстрактным методом в качестве функционального интерфейса в Java, вы можете передавать его экземпляры вместо лямбда-выражений. Это тоже возможно в Kotlin, но на самом деле Kotlin предоставляет более простой синтаксис для этого. Когда вам нужно использовать функциональный интерфейс в Kotlin, вы можете передать lambda-выражение, которое соответствует сигнатуре единственного метода интерфейса, вместо экземпляра интерфейса. Компилятор сам преобразует лямбда-выражение в экземпляр интерфейса, используя функцию-расширение метода invoke интерфейса.
#вопросы_с_собеседований

Вопрос по Swift

Могли бы вы объяснить, как работают GCD (Grand Central Dispatch) и OperationQueue в Swift для управления многопоточностью? В чём различия между этими двумя подходами и в каких ситуациях предпочтительнее использовать тот или иной?

Grand Central Dispatch (GCD) — низкоуровневая API для многопоточности в Swift, которая позволяет выполнять асинхронные задачи в параллельных очередях. GCD удобен для выполнения простых асинхронных операций и управляет пулом потоков автоматически.

Пример использования GCD:

DispatchQueue.global().async {
// Выполнение задачи в фоновом потоке
let result = performSomeTask()

DispatchQueue.main.async {
// Обновление UI в главном потоке
updateUI(with: result)
}
}

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

Пример использования OperationQueue:

let operationQueue = OperationQueue()
let operation = BlockOperation {
// Выполнение задачи
performSomeTask()
}
operationQueue.addOperation(operation)

Выбор между GCD и OperationQueue зависит от сложности задачи. Для простых асинхронных операций удобнее использовать GCD, а для более сложных сценариев с зависимостями между задачами — OperationQueue.
#вопросы_с_собеседований

Вопрос по Kotlin

Что такое Layouts, какие виды вы знаете и как их применять?

Layouts в Android — это структуры, которые определяют расположение элементов интерфейса на экране. Некоторые из основных типов layouts и их особенности:

1. LinearLayout: располагает дочерние элементы в вертикальном или горизонтальном направлении. Прост в использовании и идеален для создания линейных структур, таких как списки и полосы кнопок.

2. RelativeLayout: позволяет дочерним элементам указывать своё положение относительно других элементов или родительского контейнера. Используется для более сложных макетов, где требуется точное позиционирование элементов.

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

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

5. GridLayout: выстраивает элементы в двумерной сетке. Подходит для создания компактных, табличных макетов.

6. TableLayout: группирует элементы в ряды и колонны, подобно таблицам в HTML. Подходит для простых табличных макетов без сложной стилизации.

Применение каждого из этих layouts зависит от конкретных задач, которые вы хотите решить в вашем приложении.
#вопросы_с_собеседований

Вопрос по Kotlin

Что такое инфиксная функция в Kotlin?

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

Пример:

class Operations {
var x = 10;
infix fun minus(num: Int) {
this.x = this.x — num
}
}

fun main() {
val opr = Operations()
opr minus 8
print(opr.x)
}
#вопросы_с_собеседований

Вопрос по Swift

🤔 Как бы вы реализовали «ленивую» загрузку изображений?

Для «ленивой» загрузки изображений обычно используют комбинацию кэширования и асинхронной загрузки. Библиотеки типа SDWebImage или AlamofireImage могут оказать неоценимую помощь. Эти библиотеки получают изображение в фоновом режиме, позволяя пользовательскому интерфейсу оставаться отзывчивым, и кэшируют его для последующего использования, экономя таким образом полосу пропускания.
#вопросы_с_собеседований

Вопрос по Swift

Что такое Семафор в Swift?

Семафор в программировании — это средство синхронизации, используемое для управления доступом к общим ресурсам несколькими потоками.

В Swift семафор представлен классом DispatchSemaphore, который входит в библиотеку Grand Central Dispatch (GCD). GCD предлагает простой и эффективный способ управления параллельностью в многозадачных приложениях. Класс DispatchSemaphore имеет два основных метода: signal() и wait(). Метод signal() увеличивает значение семафора на единицу, в то время как wait() уменьшает его на единицу. Если значение семафора меньше или равно нулю, метод wait() блокирует поток до того момента, пока значение семафора не станет больше нуля.

Сценарий использования семафора в Swift может выглядеть следующим образом:

import Foundation

let semaphore = DispatchSemaphore(value: 1)

// Поток 1
DispatchQueue.global().async {
semaphore.wait()
// Критическая секция
print(«Поток 1 внутри критической секции»)
sleep(2)
semaphore.signal()
}

// Поток 2
DispatchQueue.global().async {
semaphore.wait()
// Критическая секция
print(«Поток 2 внутри критической секции»)
semaphore.signal()
}

// Ожидание завершения всех операций
DispatchQueue.global().sync {
// ...
}
#вопросы_с_собеседований

📱 Kotlin

➡️ Как активность реагирует, когда пользователь поворачивает экран?

При повороте экрана текущий экземпляр активности уничтожается и создается новый экземпляр активности в новой ориентации. Метод onRestart() вызывается первым при повороте экрана. Остальные методы жизненного цикла вызываются в том же порядке, что и при первом создании активности.
Please open Telegram to view this post
VIEW IN TELEGRAM
#вопросы_с_собеседований

🐦 Swift

Что такое паттерн Singleton и где он может быть полезен?

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

Пример синглтона:

class NetworkManager {
static let shared = NetworkManager()

private init() {
// Инициализация сетевых конфигураций или задач
}

func fetchData(from url: URL, completion:
@escaping (Data?, Error?) -> Void) {
URLSession.shared.dataTask(with: url) { data, response, error in
DispatchQueue.main.async {
completion(data, error)
}
}.resume()
}
}

В этом примере NetworkManager имеет статическое свойство shared, которое хранит единственный экземпляр класса.
#вопросы_с_собеседований

🤖 Kotlin

Зачем нужен класс Nothing в Kotlin?

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

Рассмотрим несколько сценариев, когда Nothing может быть использован:

1. Функции, выбрасывающие исключение:

fun throwError(): Nothing {
throw RuntimeException(«This function always throws an exception.»)
}

В этом примере функция throwError возвращает тип Nothing, поскольку она всегда выбрасывает исключение и не возвращает нормальное значение.

2. Бесконечные циклы:

fun infiniteLoop(): Nothing {
while (true) {
// код, который никогда не завершится
}
}

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

3. Процессы, которые не могут завершиться нормально:

fun launchRocket(): Nothing {
// код запуска ракеты, который не может завершиться нормально
}

Функции, представляющие процессы, которые не могут завершиться нормально, могут использовать Nothing в качестве типа возвращаемого значения.
Please open Telegram to view this post
VIEW IN TELEGRAM
#вопросы_с_собеседований

🐦 Swift

Как вы оптимизируете производительность UITableView в сложном приложении? Опишите различные техники и подходы, которые вы использовали бы.

Ответ:

Оптимизация производительности UITableView является ключевым аспектом при разработке iOS-приложений, особенно когда она содержит большое количество или сложные данные. Вот несколько подходов:

Ленивая загрузка изображений: Это означает загрузку изображений асинхронно и только при необходимости. Это снижает время загрузки и уменьшает использование памяти.

Использование Reuse Identifier: Эффективное использование идентификаторов повторного использования для ячеек помогает уменьшить нагрузку на память и улучшить скорость прокрутки, поскольку UITableView не будет создавать новую ячейку каждый раз при прокрутке.

Оптимизация макета ячеек: Использование Auto Layout может быть ресурсоемким. Старайтесь упростить макеты ячеек, минимизируя количество ограничений и вложенных представлений.

Использование prefetching данных: iOS предоставляет API для предварительной загрузки данных, что позволяет заранее подготовить данные, которые скоро будут отображаться.

Оптимизация вычислений в методах DataSource и Delegate: Убедитесь, что методы, такие как cellForRowAt и heightForRowAt, выполняются быстро и не содержат ресурсоемких операций.

Ограничение количества анимаций и сложных графических операций: Чрезмерное использование анимаций и сложных графических эффектов может замедлить прокрутку.
#вопросы_с_собеседований

💻 Swift

В чем разница Weak и Unowned в Swift?

Weak (Слабая ссылка):

weak используется, когда ссылка на объект не должна увеличивать счетчик ссылок объекта.
Если объект, на который указывает weak ссылка, был освобожден, weak ссылка автоматически становится nil.
Опциональный тип используется для weak ссылок, так как они могут быть автоматически устанавливаемыми в nil.

class Person {
var apartment: Apartment?
}

class Apartment {
weak var tenant: Person?
}

Unowned (Неудерживаемая ссылка):

unowned также не увеличивает счетчик ссылок объекта, но предполагается, что объект, на который указывает unowned ссылка, всегда существует (не может быть nil).
Если объект, на который указывает unowned ссылка, был освобожден, попытка доступа к этой ссылке приведет к краху приложения.
Используется, когда можно гарантировать, что объект, на который указывает ссылка, будет существовать до тех пор, пока существует unowned ссылка.

class Customer {
var creditCard: CreditCard?
}

class CreditCard {
unowned var owner: Customer
}

Выбор между weak и unowned зависит от сценария использования. Если объект, на который указывает ссылка, может быть освобожден и ссылка может стать nil, то используйте weak. Если вы уверены, что объект всегда будет существовать, используйте unowned. Ошибочное использование unowned в случае, когда объект может быть освобожден, приведет к краху приложения из-за доступа к освобожденной памяти.
Please open Telegram to view this post
VIEW IN TELEGRAM
#вопросы_с_собеседований

💻 Kotlin

Что такое Object в Kotlin?

В Kotlin ключевое слово Object используется для создания объекта-одиночки (singleton). Объект-одиночка представляет собой класс, у которого может быть только один экземпляр, и этот экземпляр предоставляет глобальную точку доступа к нему. Объект-одиночка полезен, когда требуется иметь единственный экземпляр класса, который обеспечивает доступ к каким-то ресурсам, например, базе данных, конфигурационным параметрам или службам.

Пример использования Object:

object Singleton {
// свойства и методы объекта-одиночки
fun doSomething() {
println(«Doing something...»)
}
}

fun main() {
// Использование объекта-одиночки
Singleton.doSomething()
}

В примере Singleton представляет собой объект-одиночку, и у него может быть только один экземпляр. Вызов Singleton.doSomething() демонстрирует использование объекта для выполнения какой-то функциональности. Этот подход гарантирует, что экземпляр класса будет создан только один раз, и к нему можно обращаться из любого места программы.
Please open Telegram to view this post
VIEW IN TELEGRAM
#вопросы_с_собеседований

💻 Swift

Можете ли вы объяснить, как автоматический счетчик ссылок (ARC) в Swift управляет памятью, особенно уделяя внимание различиям между сильными, слабыми и бесхозными ссылками, и как битовые поля и битовые операции играют роль в этом процессе?

Ответ:

В Swift ARC автоматизирует управление памятью, отслеживая и управляя ссылками на объекты. Сильные ссылки сохраняют объект в памяти, а слабые и бесхозные — нет. Слабые ссылки позволяют избежать циклов сохранения и превращаются в nil при деаллокации объекта, в то время как бесхозные ссылки предполагают, что объект всегда существует, и могут привести к ошибкам во время выполнения, если к нему обращаются после деаллокации.

Внутри ARC использует битовые поля и побитовые операции для эффективного отслеживания этих ссылок. Например, он хранит количество ссылок в битовом поле в структуре HeapObject. Эта система обеспечивает эффективное управление памятью, предотвращая утечки и сохраняя циклы.
Please open Telegram to view this post
VIEW IN TELEGRAM
#вопросы_с_собеседований

💻 Swift

Что такое lazy stored properties в Swift и в каких случаях
их следует использовать?

Ответ:

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

Пример использования:

class DataManager t
lazy var cachedData: [String] = {
// Здесь происходит сложная операция загрузки данных
// Например, загрузка данных из сети или базы данных
return loadCachedData)
}()

func loadCachedData() -> [String] {
// Загрузка данных из какого-либо источника
return [«Data 1», «Data 2», «Data 3»]


let manager = DataManager ()
// Первое обращение к свойству cachedData вызывает его инициализацию
print (manager. cachedData) // [«Data 1», «Data 2», «Data 3»]
Please open Telegram to view this post
VIEW IN TELEGRAM
#вопросы_с_собеседований

Вопрос по Kotlin

Как реализовать архитектуру MVVM в приложении для Android с помощью Jetpack?

Ответ:

Чтобы реализовать MVVM-архитектуру с помощью Jetpack, можно использовать следующие компоненты:

• LiveData: Наблюдаемый держатель данных, учитывающий жизненный цикл, который может использоваться для передачи изменений между компонентами ViewModel и View.
• ViewModel: Класс, который хранит и управляет данными, связанными с пользовательским интерфейсом, взаимодействует с компонентом Model и выживает после изменения конфигурации.
• DataBinding: Библиотека, позволяющая компонентам UI привязываться к источникам данных во ViewModel и устраняющая необходимость в вызовах findViewById(). Вы также можете использовать другие компоненты Jetpack, такие как Room для работы с базой данных, Navigation для перемещения между экранами и WorkManager для фоновой обработки данных.
#вопросы_с_собеседований

Swift

Вопрос: назовите известные проблемы с многопоточностью?

Ответ:

Многопоточность — это мощный инструмент в разработке ПО, который позволяет вашему приложению выполнять несколько задач одновременно. Однако с её мощностью приходят и сложности. Вот некоторые из проблем:

1. Состояние гонки (Race Conditions): Это происходит, когда два или более потока пытаются одновременно изменить общие данные. Результат выполнения таких операций может зависеть от того, в каком порядке выполняются потоки, что может привести к непредсказуемому поведению программы.


var sharedResource = [String]()

DispatchQueue.global().async {
for _ in 0..<1000 {
sharedResource.append("A")
}
}

DispatchQueue.global().async {
for _ in 0..<1000 {
sharedResource.append("B")
}
}
// Предполагаемый результат может быть непредсказуемым, так как оба потока работают с одним и тем же ресурсом одновременно.


2. Взаимная блокировка (Deadlocks): Взаимная блокировка может произойти, когда два или более потока блокируются, ожидая, пока другие потоки освободят ресурсы, которые они уже удерживают, в результате чего ни один из потоков не может продолжить выполнение.


let queue1 = DispatchQueue(label: "queue1")
let queue2 = DispatchQueue(label: "queue2")

queue1.async {
queue2.sync {
// Делаем что-то
}
}

queue2.async {
queue1.sync {
// Делаем что-то
}
}
// Здесь потоки будут ждать друг друга бесконечно, создавая взаимную блокировку.


3. Условия гонки при работе с памятью (Memory Races): Похоже на условия гонки, но здесь конфликт возникает при доступе к памяти. Это может привести к повреждению данных, когда несколько потоков пытаются одновременно читать и записывать данные в одно и то же место в памяти без должной синхронизации.

4. Голодание (Starvation): Происходит, когда поток никогда не получает доступ к ресурсу или исполнителю из-за постоянного захвата этих ресурсов другими потоками.

5. Чрезмерная синхронизация (Over-Synchronization): Происходит, когда для предотвращения проблем с многопоточностью добавляется слишком много блокировок, что в свою очередь может серьёзно снизить производительность программы, так как потоки часто ожидают возможности доступа к ресурсам.

Чтобы избежать этих и других проблем с многопоточностью, разработчики используют различные техники синхронизации, такие как блокировки, семафоры и барьеры. Однако нужно быть осторожным, чтобы не переусложнить программу и не снизить её производительность.
#вопросы_с_собеседований

Kotlin

Вопрос: В чем преимущество Kotlin для разработки под Android?

Ответ:

1. Более краткий и выразительный синтаксис: Kotlin позволяет писать код более кратко и чисто по сравнению с Java, сокращая количество шаблонного кода. Это делает код легче для чтения и поддержки.

2. Null безопасность: В Kotlin встроена поддержка обработки значений `null`, что помогает избежать `NullPointerException` — одной из наиболее распространенных ошибок в Java-приложениях.

3. Расширенные функции (Extension functions): Kotlin позволяет добавлять новые функции к существующим классам без их модификации. Это упрощает работу с API Android, делая код более читабельным и лаконичным.

4. Поддержка функционального программирования: Kotlin включает множество функций функционального программирования, таких как лямбда-выражения, высшие порядки функций, которые делают код более гибким и выразительным.

5. Полная совместимость с Java: Kotlin полностью совместим с Java, что позволяет легко использовать все существующие Java-библиотеки и фреймворки в Kotlin-проектах, а также постепенно переводить существующий Java-код на Kotlin.

6. Инструментальная поддержка: Kotlin полностью поддерживается в Android Studio, что обеспечивает удобные инструменты для разработки, такие как автодополнение, рефакторинг кода, проверка ошибок в реальном времени.

7. Корутины для асинхронного программирования: Kotlin предоставляет встроенную поддержку корутин, что упрощает работу с асинхронными операциями, такими как выполнение сетевых запросов или чтение из базы данных, делая код более понятным и менее подверженным ошибкам.

8. Улучшенная безопасность: Благодаря более строгой системе типов и обработке исключений, Kotlin помогает предотвратить распространенные ошибки во время компиляции, что повышает общую безопасность приложения.

9. Официальная поддержка Google: С 2017 года Kotlin является официальным языком для разработки Android-приложений, что гарантирует его постоянное обновление и поддержку со стороны Google.