├── .gitignore └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | # 3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 4 | 5 | ## User settings 6 | xcuserdata/ 7 | 8 | ## compatibility with Xcode 8 and earlier (ignoring not required starting Xcode 9) 9 | *.xcscmblueprint 10 | *.xccheckout 11 | 12 | ## compatibility with Xcode 3 and earlier (ignoring not required starting Xcode 4) 13 | build/ 14 | DerivedData/ 15 | *.moved-aside 16 | *.pbxuser 17 | !default.pbxuser 18 | *.mode1v3 19 | !default.mode1v3 20 | *.mode2v3 21 | !default.mode2v3 22 | *.perspectivev3 23 | !default.perspectivev3 24 | 25 | ## Obj-C/Swift specific 26 | *.hmap 27 | 28 | ## App packaging 29 | *.ipa 30 | *.dSYM.zip 31 | *.dSYM 32 | 33 | ## Playgrounds 34 | timeline.xctimeline 35 | playground.xcworkspace 36 | 37 | # Swift Package Manager 38 | # 39 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies. 40 | # Packages/ 41 | # Package.pins 42 | # Package.resolved 43 | # *.xcodeproj 44 | # 45 | # Xcode automatically generates this directory with a .xcworkspacedata file and xcuserdata 46 | # hence it is not needed unless you have added a package configuration file to your project 47 | # .swiftpm 48 | 49 | .build/ 50 | 51 | # CocoaPods 52 | # 53 | # We recommend against adding the Pods directory to your .gitignore. However 54 | # you should judge for yourself, the pros and cons are mentioned at: 55 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 56 | # 57 | # Pods/ 58 | # 59 | # Add this line if you want to avoid checking in source code from the Xcode workspace 60 | # *.xcworkspace 61 | 62 | # Carthage 63 | # 64 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 65 | # Carthage/Checkouts 66 | 67 | Carthage/Build/ 68 | 69 | # Accio dependency management 70 | Dependencies/ 71 | .accio/ 72 | 73 | # fastlane 74 | # 75 | # It is recommended to not store the screenshots in the git repo. 76 | # Instead, use fastlane to re-generate the screenshots whenever they are needed. 77 | # For more information about the recommended setup visit: 78 | # https://docs.fastlane.tools/best-practices/source-control/#source-control 79 | 80 | fastlane/report.xml 81 | fastlane/Preview.html 82 | fastlane/screenshots/**/*.png 83 | fastlane/test_output 84 | 85 | # Code Injection 86 | # 87 | # After new code Injection tools there's a generated folder /iOSInjectionProject 88 | # https://github.com/johnno1962/injectionforxcode 89 | 90 | iOSInjectionProject/ 91 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Вопросы на собеседовании iOS разработчика. 2 | 3 | Здесь собраны на мой взгляд самые распространненные вопросы на собеседовании iOS разработчиков разного уровня. К большинству из них даны ответы и примеры кода, где это необходимо. Ниже представлена легенда, по которой я буду маркировать вопросы разного уровня. Данная маркировка весьма условна и лишь является моим видением того, какую информацию человек должен знать, если он претендует на тот или иной уровнеь. Каждый следующий уровень включает в себя все вопросы предыдущего. 4 | 5 | ## Легенда 6 | 7 | 🟢 - `Junior` уровень 8 | 🟡 - `Middle` уровень 9 | 🔴 - `Senior` уровень 10 | 11 | ##### Пример кода: 12 | 13 | ```swift 14 | let example = "Hello, Example!" 15 | ``` 16 | > Мои комментарии 17 | 18 | ## Общие вопросы 19 | 20 | ### 1. 🟢 Назовите основные принципы `OOP`. 21 | 22 | Три основных принципа `OOP` - Инкапсуляция, Наследование, Полиморфизм. 23 | 24 | Инкапсуляция - механизм изолирования реализации (переменных и функций) под область видимости одного типа. 25 | Наследование - механизм, при котором один тип может получить все свойства другого типа, который является его предком. 26 | Полиморфизм - механим представления одного типа через другой тип, при условии, что оба типа являются родственниками. 27 | 28 | > Наверное, самый стандартный и одновременно всех задолбавший вопрос на собеседовании, без которого, наверное, планета уже давно сошла бы с оси. 29 | 30 |
31 | 32 | ### 2. 🟢 Что такое `POP` (`Protocol Oriented Programming`)? Чем отличается `POP` от `OOP`? 33 | 34 | `POP` - Protocol Oriented Programming, подход, при котором структура программы реализуется через протоколы (интерфейсы) и их реализацию. `POP` отличается от `OOP` тем, что при использовании `POP`, вы создаете протоколы, которые затем реализуют ваши типы, а не создаете типы, которые потом необходимо наследовать. 35 | 36 | > На заре Swift эры `POP` был очень популярным, но все больше и больше уходит со сцены в пользу композиции. 37 | 38 |
39 | 40 | ### 3. 🟢 Чем отличается фукнция от метода? 41 | 42 | Функция отличается от метода областью видимости. Функцию можно вызвать глобально и она не привязана ни к какому типу, в то время, как метод можно вызвать только у экземпляра типа. При этом метод имеет доступ ко всем полям и другим методам данного экзепляра. 43 | 44 |
45 | 46 | ### 4. 🟢 Что такое рекурсия? Как ее правильно использовать и какие у нее есть нюансы? 47 | 48 | `Рекурсия` - это механизм, который позволяет функции вызвать саму себя. При неосторожном использовании рекурсии, программа может провалиться в бесконечный цикл вызовов, что в итоге приведет к крашу в тот момент, когда переполнится стэк вызова функций. Для того, чтобы избежать подобного сценария у рекурсии должно быть так называемое `дно` - точка выхода из рекурсии, где функция больше не вызывает саму себя. 49 | 50 |
51 | 52 | ### 5. 🟢 Что такое `Big-O notation`? Для чего используется? 53 | 54 | `Big-O notation` - показатель сложности алгоритма. Данный показатель может использоваться для оценки сложности алгоритма по скорости или по памяти. 55 | 56 | > Этот вопрос очень любят, рекомендую изучить данную тему. 57 | 58 |
59 | 60 | ### 6. 🟡 Что такое `KVO`/`KVM`? Для чего их исользуют? 61 | 62 | `KVO` - Key-Value Observing - механизм, при котором мы можем отслеживать изменения свойства экземпляра, получая доступ к данному свойству по ключу. 63 | `KVM` - Key-Value Modification - механизм, который позволяет нам модифицировать свойство экземпляра, получая доступ к данному свойству по ключу. 64 | 65 | На примере Swift KVO/KVM - это KeyPath. 66 | 67 | > Данный вопрос встречается довольно редко, поэтому многих может застать врасплох. 68 | 69 |
70 | 71 | ### 7. 🟡 Какие алгоритмы поиска и сортировки вы знаете? Какие исользуете в работе? 72 | 73 | Здесь я рекомендую назвать только те, которые вы реально знаете, так как их могут попросить реализовать на месте. Если вы знаете и помните наизусть много алгоритмов, можете назвать пару-тройку из них. 74 | 75 | > Лично я крайне негативно отношусь к данному вопросу, так как все мы прекрасно понимаем, что в реальности в 99% случаях будет использованы `sort()` и `filter()` из стандартной библиотеки. 76 | 77 |
78 | 79 | ### 8. 🟡 Что такое реактивное программирование? Есть ли опыт написания программ реактивно? 80 | 81 | `Реактивное программирование` - программирование, при котором общение между объектами программы происходит посредством налаживанием каналов связи между объектами. Реактивный подход очень активно использует функциональное программирование - тип программирования, при котором значения не хранятся в переменных, а высчитываются, пропускаясь через цепочку функций. 82 | 83 | > Если у вас есть опыт реакта, рекомендую четко указывать, каким фреймворком для этого пользовались. К примеру, `RxSwift` и `Combine` имеют очень много различий и умение пользоваться одним не так легко проэцируется на другой. 84 | 85 |
86 | 87 | ### 9. 🟡 Что такое `Future/Promise`? 88 | 89 | `Future` или `Promise` - два названия одного и того же подхода, одного из способов реализации рективного программирования. Это прокси (контейнер), в котором должно быть значение в каком-то времени в будущем. Изначально данный контейнер может быть пуст и при попытки получить его значение, выполнение программы блокируется до тех пор, пока значение в контейнере не появится. 90 | 91 |
92 | 93 | ### 10. 🟡 Что такое `Publisher`/`Subscriber`? 94 | 95 | `Publisher` и `Subscriber` - это еще один подход, с помощью которого возможна реализация реактивного программирования. 96 | `Publisher` - объект, который выдает значения в течении некоторого или неограниченного времени. 97 | `Subscriber` - объект, который подписывается на выдачу значений `publisher`'a и обрабатывает получаемые значения от него. 98 | 99 | > Приведенные термины взяты из `Combine`. В `RxSwift`, к примеру, другая и более обширная терминология. 100 | 101 |
102 | 103 | ### 11. 🔴 Что такое слабосвязанный код? В чем его преимущество перед сильносвязанным? 104 | 105 | `Слабосвязанный код` - это код, который написан такм образом, при котором один фрагмент кода может быть заменен на другой фрагмент кода, не требуя при этом изменений в других фрагментах кода. Как правило это достигается при помощи протоколов и интерфейсов. Преимущество перед сильносвязанным кодом в том, что мы можем с куда меньшими затратами сил и времени менять часть программы. 106 | 107 | ```swift 108 | protocol ColorProvider { 109 | var color: UIColor { get } 110 | } 111 | 112 | struct LCDColorProvider: ColorProvider { 113 | var color: UIColor { 114 | UIColor(red: 0.3, green: 0.24, blue: 0.71, alpha: 1) 115 | } 116 | } 117 | 118 | struct P3ColorProvider: ColorProvider { 119 | var color: UIColor { 120 | UIColor(displayP3Red: 0.32, green: 0.264, blue: 0.7142, alpha: 1) 121 | } 122 | } 123 | 124 | struct ColorSettings { 125 | var colorProvider: ColorProvider 126 | } 127 | 128 | let lcdSettings = ColorSettings(colorProvider: LCDColorProvider()) 129 | let p3Settings = ColorSettings(colorProvider: P3ColorProvider()) 130 | ``` 131 | 132 |
133 | 134 | ### 12. 🔴 Как вы оптимизируете время компиляции программы? 135 | 136 | Вопрос достаточно обширный и зависит от методов и предпочтений каждого. Можете перечислить все, что вы используете, желательно максимально детально. 137 | 138 | > Рассказать про уменьшение зависимостей и графа билда никогда не будет лишним. 139 | 140 |
141 | 142 | ### 13. 🔴 Как вы оптимизируете время запуска программы? 143 | 144 | Аналогично предыдущему вопросу, просто перечисляем все способы, которые реально использовали на практике. Существует несколько самых распространенных способов данной оптимизации, они довольно легко ищутся в интернете. 145 | 146 |
147 | 148 | ## Swift 149 | 150 | ### 1. 🟢 Какие структуры данных есть в Swift? 151 | 152 | В Swift существуют следующие структуры данных: 153 | * `enum` 154 | * `struct` 155 | * `class` 156 | * `actor` 157 | * `protocol` 158 | 159 | > Описание каждой структуры с легкостью находятся в книге The Swift Programming Language. 160 | 161 |
162 | 163 | ### 2. 🟢 Каике структуры данных относятся к `value type`? Какие к `reference type`? 164 | 165 | К `value type` относятся `enum` и `struct`. 166 | К `reference type` относятся `class`, `actor`. Так же к `reference type` относятся `closure` и `func`, хоть они и не являются структурами данных. 167 | 168 |
169 | 170 | ### 3. 🟢 В чем отличие `value type` и `reference type` с точки зрения памяти и хранения? 171 | 172 | Экземпляры `value type` хранятся в стеке (stack), в то время, как `reference type` хранятся в куче (heap). 173 | Так же, при присваивании одного экземпляра `value type` другому экземпляру того же типа, происходит копирование из одного экземпляра в другой, в то время, как при присваивании одного экземпляра `reference type` другому экземпляру того же типа, происходит копирование ссылки на объект, а не самого объекта. 174 | 175 |
176 | 177 | ### 4. 🟢 Что такое `closure` и зачем они нужны? Чем отличаются от `func`? 178 | 179 | `closure` или замыкания - это анонимные функции, которые не могут принадлежать типу, но могут храниться в переменной. Так же `closure` можно определить в том месте, где ожидается параметр-функция. По своей сути `closure` и `func` - это одно и тоже. 180 | 181 |
182 | 183 | ### 5. 🟢 Что такое `escaping` и `nonescaping`? Для чего они используются? 184 | 185 | `escaping` и `nonescaping` - ключевые слова, применимые только к параметрам функции, типом которых является функция. Являются механизмом оптимизации выполнения кода. 186 | `escaping` - сигнализирует компилятору, что функция-параметр может быть вызвана после того, как выполнение тела вызывающей ее функции закончится. 187 | `nonescaping`, соотвественно, гарантирует, что функция-параметр не будет вызвана после того, как тело вызывающей ее функции завершится. 188 | По умолчанию все параметры-функции - `nonescaping`, за исключением, если они не являются `optional`. 189 | 190 |
191 | 192 | ### 6. 🟢 Что такое capture list? Для чего он используется? 193 | 194 | `Capture list` или список захвата - это механизм, использующийся в замыканиях. Благодаря ему замыкание имеет доступ к переменным/константам, объявленными за пределами тела замыкания, а так же к полям типа, внутри которого объявлено замыкание. По умолчанию, все переменные/константы, объявленные внутри функции, в которой объявлено замыкание, попадают в список захвата замыкания. Если данные переменные/константы являются экземплярами `reference type` типов, то они захватываются сильной ссылкой. 195 | `self` по умолчанию не захватывается, но любое упоминание self внутри замыкания автоматически добавляет его в список захвата сильной ссылкой, если `self` - экземпляр `reference type`. 196 | Список захвата необходим замыканию для того, чтобы была возможность работать с данными, которые объявлены за пределами тела замыкания. 197 | 198 |
199 | 200 | ### 7. 🟢 `closure` - это `value type` или `reference type`? Почему? А `func`? 201 | 202 | `closure` - это `reference type`. Если бы `closure` была бы `value type`, то при передаче ее в функцию, она бы копировалась, что привело бы к копированию всех объектов, которые попадают в ее список захвата и потерю контекста, где `closure` была определена. 203 | `func` - это так же `reference type`. По своей сути `closure` и `func` - это одно и тоже, так что и "под капотом" они реализованы одинаково. 204 | 205 |
206 | 207 | ### 8. 🟢 Что такое `CoW` (Copy on Write)? Как и где он реализован в Swift? 208 | 209 | `CoW` - это механизм, при котором при присваивании одного экземпляра другому, копирование объекта не происходит до тех пор, пока один из экземпляров не будет модифицирован. Данный механизм используется во всех `value type` типах в Swift. 210 | 211 |
212 | 213 | ### 9. 🟢 Что такое `mutating`? 214 | 215 | `mutating` - это ключевое слово в Swift, которое позволяет методу, указанному как `mutating`, менять `self` в `value type` типах. По умолчанию все методы `value type` типов `nonmutating`. 216 | 217 |
218 | 219 | ### 10. 🟢 В чем отличие между `var` и `let`? Есть ли разница между `value type` и `reference type` с точки зрения `var` и `let`? 220 | 221 | `var` - ключевое слово для объявления переменной. 222 | `let` - ключевое слово для объявления константы. 223 | 224 | Переменные `value type` и `reference type` ведут себя одинаково. 225 | Константе `value type` не может быть присвоен другой экземпляр данного типа, а так же все ее внутренние поля не могут быть изменены. 226 | Константе `reference type` не может быть присвоен другой экземпляр данного типа, но ее внутренние неконстантные поля могут быть изменены. 227 | 228 |
229 | 230 | ### 11. 🟢 Назовите все уровни доступа и что они означают в Swift? 231 | 232 | `private` - самый закрытый уровень доступа. Поля и методы типа с данным уровнем доступа видны только внутри объявления типа и расширениях, объявленных в том же файле, что и сам тип. 233 | `fileprivate` - поля и методы типа с данным уровнем доступа видны снаружи объявления типа, но только в пределах файла, в котором объявлен тип. 234 | `internal` - уровень доступа по умолчанию. Поля и методы типа видны снаружи объявления типа в пределах модуля, в котором объявлен тип. 235 | `public` - поля и методы типа видны снаружи объявления типа внутри и за пределами модуля, в котором объявлен тип. Однако, за пределами данного модуля тип с данным уровнем доступа не может быть наследован, а поля и методы перегружены. 236 | `package` - поля и методы типа видны снаружи объявления типа в пределах Swift Package (все таргеты), в котором объявлен этот тип. 237 | `open` - самый открытый уровень доступа. Тоже самое, что и `public`, но наследование и перегрузка не запрещены. 238 | 239 |
240 | 241 | ### 12. 🟢 Чем отличается `public` и `open`? 242 | 243 | `public` типы не могут наследоваться, а `public` поля и методы не могут перегружаться за пределами модуля, в котором объявлен тип. 244 | `open` типы могут наследоваться, а `open` поля и методы могут перегружаться за пределами модуля, в котором объявлен тип. 245 | 246 |
247 | 248 | ### 13. 🟢 Что такое `final`? 249 | 250 | `final` - ключевое слово, которое запрещает дальнейшее наследование типа или перегрузку поля или метода типа. 251 | 252 |
253 | 254 | ### 14. 🟢 Назовите особенности `enum` в Swift 255 | 256 | `enum` в Swift может иметь `rawValue` отличный от `Int`, в отличии от многих языков программирования. Так же, каждое значение перечисления может иметь вложенные значения любого типа в любом количестве, включая данное перечисление. Если вложенное значение является данным перечислением, перед объявлением данного значения ставится ключевое слово `indirect`. 257 | 258 | > Не лишним будет упомянуть, что `enum` - это прекрасное место для хранения статических констант или функций. 259 | 260 |
261 | 262 | ### 15. 🟢 Что такое `Optional`? 263 | 264 | `Optional` - специальное перечисление в Swift, которое позволяет показать, что значение отсутствует, что обозначается ключевым словом `nil`. 265 | 266 |
267 | 268 | ### 16. 🟢 Что такое `if let`? 269 | 270 | `if let` - это конструкция безопасного разворачивания `Optional`. Код внутри блока `if let` будет выполнен только в том случае, если проверяемый `Optional` не равен `nil`. 271 | 272 | ```swift 273 | var myNumber: Int? = 12 274 | if let number = myNumber { 275 | print("My number is \(number)") // prints Mu number is 12 276 | } 277 | ``` 278 | 279 |
280 | 281 | ### 17. 🟢 Что такое `guard`? 282 | 283 | `guard` - это ключевое слово контроля выполнения кода, которое проверяет условие на истинность. У `guard` есть только блок `else`, который выполнится, если условие не действительно. `else` блок `guard` обязан прервать выполнение блока кода, в котором объявлен `guard`. 284 | 285 | ```swift 286 | func increment(number: Int) -> Int { 287 | guard number >= 10 else { 288 | return number 289 | } 290 | 291 | return number + 1 292 | } 293 | 294 | let incrementedNumber = increment(number: 4) // result is 5 295 | let notIncrementedNumber = increment(number: 13) // result is 13 296 | ``` 297 | 298 |
299 | 300 | ### 18. 🟢 В чем разница между `if let` и `guard let`? 301 | 302 | Обе данных конструкции безопасно разворачивают `Optional` и выполняют блок кода только в том случае, если значение `Optional` не равно `nil`. Единственное различие в том, что `else` блок `guard` обязан выйти из блока кода, где был объявлен `guard`. 303 | 304 |
305 | 306 | ### 19. 🟢 Что делают операторы `?`, `!` и `??`? 307 | 308 | Оператор `?` - это оператор опционального связывания при доступе к значению `Optional`. 309 | 310 | ```swift 311 | struct Person { 312 | var name: String 313 | var lastName: String 314 | } 315 | 316 | var me: Person? = Person(name: "Karl", lastName: "Brown") 317 | me?.name = "Mark" 318 | ``` 319 | 320 | Оператор `!` - это оператор небезопасного разворачивания `Optional`. Должен использоваться только тогда, когда вы на 100% уверенны, что значение `Optional` не равно `nil`. 321 | 322 | ```swift 323 | var number: Int? = 10 324 | var noNumber: Int? 325 | 326 | print(number!) // ok, prints 10 327 | print(noNumber!) // crash, unexpectedly found nil while unwrapping an optional value 328 | ``` 329 | 330 | Оператор `??` - это оператор безопасного разворачивания `Optional` и использования его значения или предоставления значения по умолчанию, если значение `Optional` равно `nil`. 331 | 332 | ```swift 333 | var number: Int? = 10 334 | var noNumber: Int? 335 | 336 | print(number ?? 12) // prints 10 337 | print(noNumber ?? 12) // prints 12 338 | ``` 339 | 340 |
341 | 342 | ### 20. 🟢 Что такое `extension`? Что может быть в `extension`, а чего нет? 343 | 344 | `extension` или расширение - дополнение уже существующего типа. Расширить можно любой тип или протокол. `extension` может содержать методы, вычисляемые переменные, статические переменные/константы/методы. `extension` не может объявлять хранимые переменные/константы. `extension` не может перегружать переменные/методы, за исключением тех, которые имеют `objc` аттрибут или объявлены в `objc` коде. Однако, не рекомендуется перегружать подобные переменные/методы в любом случае, так как это может привести к неопределенному поведению системы. 345 | `extension` так же используют для предоставления протоколам реализации по умолчанию. 346 | 347 |
348 | 349 | ### 21. 🟢 Что такое `protocol`? Для чего они используются? 350 | 351 | `protocol` - особый тип данных, экземпляры которого не могут быть созданы. Протоколы описывают будущий функционал, но не реализовывают его. Имплементация протокола кладется на плечи конкретного типа, который собирается его реализовать. Протоколы используются для обеспечения менее связанного кода и предоставление гибкости при разработке, так как можно не полагаться на конкретные типы, а на протоколы. При таком подходе любой тип, который реализует протокол, может быть использован в данном месте программы. 352 | 353 |
354 | 355 | ### 22. 🟢 Что такое `Any`? Что такое `AnyObject`? Для чего они используются? 356 | 357 | `Any` - специальный тип, который является всем сразу и ничем одновременно. Каждый тип в Swift может быть привиден к типу `Any`. `Any` используется тогда, когда мы не можем использовать `generics`, но при этом хотим иметь гибкость передачи аргументов разного типа. Недостаток у такого подхода всего один: так как в итоге тип данных будет `Any`, мы должны наверняка знать, какой тип был до этого, чтобы получить возможность восстановить данные после получения. 358 | `AnyObject` - специальный тип, такой же, как и `Any`, но с ограничением только на `reference type`. Каждый `AnyObject` может быть `Any`, но не каждый `Any` может быть `AnyObject`. Ключевое слово `AnyObject` так же используется для ограничения протокола на реализацию только `reference type` типами. 359 | 360 |
361 | 362 | ### 23. 🟢 Назовите типы для работы с коллекциями, которые есть в Swift. 363 | 364 | В Swift есть три типа для работы с коллекциями - `Array`, `Set` и `Dictionary`. 365 | `Array` - массив данных. Элементы имеют порядок, доступ к элементам происходит по индексу. 366 | `Set` - неупорядоченное множество. В множестве не может быть двух одинаковых элементов. Равенство элементов достигается проверкой `hash` значения каждого элемента. В связи с этим элементы множества обязаны реализовать протокол `Hashable`. Доступ по индексу невозможен. 367 | `Dictionary` - словарь, элементы которого представляют из себя пару (ключ, значение). Ключи словаря должны быть уникальны. Это достигается ровно так же, как и в случае с множеством, через протокол `Hashable`. Значения словаря могут быть любым типом, на них не накладываются ограничения. Так же значения не должны быть уникальными. Доступ осуществляется по ключу и возвращает `Optional` значение, так как элемента по заданному ключу может не быть. Реализован через `hash table`. 368 | 369 | > Скорее всего здесь вас попросят рассказать про `hash table` поподробнее. Данный вопрос я освещать не буду, так как он чисто документальный и скорее всего никогда в жизни вам не пригодится на практике. 370 | 371 |
372 | 373 | ### 24. 🟢 Что будет, если добавить в `Set` два объекта с одинаковым значением `hash`? 374 | 375 | Если в `Set` попытаться добавить два объекта с одинаковым значением `hash`, то при добавлении первого элемента, он будет успешно добавлен в множество. При попытке добавить второй элемент в множество, элемент добавлен не будет. 376 | 377 |
378 | 379 | ### 25. 🟢 Что такое `forEach`/`map`/`flatMap`/`compactMap`/`filter`/`reduce`? Какие еще примеры функционального программирования вы знаете в Swift? 380 | 381 | `forEach`, `map`, `flatMap`, `compactMap`, `filter` и `reduce` - функции протокола `Sequence` в Swift, которые дают возможность работать с коллекциями, используя функциональный подход. 382 | В данном случае: 383 | 384 | `forEach` - выполняет блок кода для каждого элемента коллекции. 385 | 386 | ```swift 387 | let arr = [1, 2, 3, 4] 388 | arr.forEach { print($0) } 389 | 390 | // prints 391 | // 1 392 | // 2 393 | // 3 394 | // 4 395 | ``` 396 | 397 | `map` - выполняет блок кода для каждого элемента коллекции, в результате чего образовывается новая коллекция такого же размера, но тип значений коллекции может быть изменен, в зависимости от того, как реализован блок кода, который передается в `map`. 398 | 399 | ```swift 400 | let numbers = [1, 2, 3, 4] 401 | let mapped = numbers.map { 402 | Array(repeating: $0, count: $0) 403 | } // mapped = [[1], [2, 2], [3, 3, 3], [4, 4, 4, 4]] 404 | ``` 405 | 406 | `flatMap` - выполняет блок кода для каждого элемента коллекции, в результате чего образовывается новая коллекция такого же размера. Отличается от `map` тем, что, если результирующий элемент коллекции так же является коллекцией, то он будет встроен в результирующую коллекцию. Тип элементов результирующей коллекции так же может измениться, как и при выполнении `map`. 407 | 408 | ```swift 409 | let numbers = [1, 2, 3, 4] 410 | let flatMapped = numbers.flatMap { 411 | Array(repeating: $0, count: $0) 412 | } 413 | // flatMapped = [1, 2, 2, 3, 3, 3, 4, 4, 4, 4] 414 | ``` 415 | 416 | `compactMap` - выполняет блок кода для каждого элемента коллекции, в результате чего образовывается новая коллекция. Отличается от `map` тем, что размер результирующей коллекции не обязательно равен размеру изначальной. Элементы изначальной коллекции можут быть `Optional` и хранить в себе `nil`. Такой элемент не попадает в результирующую коллекцию. Тип элементов результирующей коллекции так же может измениться, как и при выполнении `map`. 417 | 418 | ```swift 419 | let numbers: [Int?] = [1, nil, 3, 4, nil] 420 | let compactMapped = numbers.compactMap { 421 | if let element = $0 { 422 | Array(repeating: element, count: element) 423 | } else { 424 | return nil 425 | } 426 | } 427 | // compactMapped = [[1], [3, 3, 3], [4, 4, 4, 4]] 428 | ``` 429 | 430 | `filter` - выполняет блок кода для каждого элемента коллекции, результатом которого есть значение `Bool`. При возврате из блока `false`, элемент исключается из результирующей коллекции. 431 | 432 | ```swift 433 | let map = [ 434 | "weather": "Good", 435 | "temperature": 27, 436 | "humidity": 34.3 437 | ] 438 | 439 | let result = map.filter { (key, _) in 440 | key == "temperature" 441 | } // result = ["temperature": 27] 442 | ``` 443 | 444 | `reduce` - выполняет блок кода для каждого элемента коллекции, результатом которого становится накопление нового результата. Используется, как правило, для получения единого результата из коллекции. 445 | 446 | ```swift 447 | let arr = [1, 2, 3, 4] 448 | let resut = arr.reduce(0) { partialResult, value in 449 | if partialResult == 0 { 450 | return value 451 | } 452 | 453 | return partialResult * 10 + value 454 | } // result = 1234 455 | ``` 456 | 457 | > Это далеко не все подобный функции коллекций, но про эти спрашивают чаще всего. 458 | 459 |
460 | 461 | ### 26. 🟢 Чем отличается `compactMap` от `flatMap`? 462 | 463 | `compactMap` - функция, которая формирует новую коллекцию из текущей, исключая все элементы, значением которых является `nil`. 464 | `flatMap` - функция, формирует новую коллекцию, "схлопывая" накопление вложенные коллекциии или `Optional` до одной коллекции или `Optional`. 465 | 466 |
467 | 468 | ### 27. 🟢 Что такое `weak` и `unowned`? Чем они отличаются? 469 | 470 | `weak` и `unowned` - это два ключевых слова для создания слабой ссылки. Применимо только к экземплярам `reference type` типов. Используются для предотвращения `reference cycle`. `weak` и `unowned` отличаются между собой так же, как и операторы `?` и `!` соответственно. `weak` не гарантирует наличия значения, в результате чего может использоваться только с `optional`. `unowned` предполагает, что значение всегда будет и, по сути, является `force unwrapped optional`. Если в процессе выполнения значение `unowned` будет `nil`, при попытке обратиться к данному значению будет краш. 471 | 472 |
473 | 474 | ### 28. 🟡 Как реализован `Optional`? 475 | 476 | Здесь можно много говорить, но лучше один раз показать, чем сто раз рассказать, так что просто воспроизводим `enum` из стандартной библиотеки. Благо он небольшой. 477 | 478 | ```swift 479 | enum Optional { 480 | case some(Wrapped) 481 | case none 482 | } 483 | ``` 484 | 485 | > Да, все так просто 486 | 487 |
488 | 489 | ### 29. 🟡 Что такое `lazy var`? Для чего она используется? 490 | 491 | `lazy var` - это переменная, инициализация которой не происходит во время инициализации экземпляра. Вместо этого инициализация `lazy var` происходит при первом обращении к этой переменной. Используется для оптимизации ресурсов, когда тяжелые или длительные операции, которые не всегда нужны, можно отложить до реальной необходимости. 492 | У `lazy var` есть интересный побочный эффект: так как инициализация данной переменной происходит после инициализации экземпляра, при инициализации `lazy var` `self` уже существует и может быть использован. 493 | 494 | > Важное уточнение, которое очень тяжело найти: ВСЕ глобальные переменные `lazy`. 495 | 496 |
497 | 498 | ### 30. 🟡 Что такое `generics`? Для чего они используются? 499 | 500 | `genrics` - аналог шаблонов из C++, механизм парметризации типов, способ уйти от конкретного типа к передачи его как параметра и обобщения функционала для разных типов. Идеальный пример - `Array`. Мы можем создать массив любых данных, но каждый такой массив будет работать одинаково, вне зависимости от типа данных, которые он хранит. 501 | 502 |
503 | 504 | ### 31. 🟡 Что такое `associated type`? Для чего он используется? 505 | 506 | `associated type` - механизм параметризации протокола. Используется для обеспечения большей гибкости работы с протоколом в силу ухода от конкретного типа к параметру. По своей сути `generics` для протокола. 507 | 508 |
509 | 510 | ### 32. 🟡 Какие ограничения есть для протоколов, у которых есть `associated type`? 511 | 512 | Так как протоколы с `assotiated type` не являются достаточно конкретными, объявить переменную данного типа или передать напрямик подобный тип как параметр функции невозможно. 513 | Здесь на помощь нам приходят ключевые слова `any` и `some`. Данные два ключевых слова решают одну и ту же проблему, но немного по-разному. 514 | `any` - создает коробку вокруг конкретного типа, который удовлетворяет данному протоколу. 515 | `some` - указывает, что пусть это не известно заранее, но на момент компиляции программы конкретный тип переменной будет известен точно. 516 | 517 |
518 | 519 | ### 33. 🟡 Чем отличается цикл `for` от `forEach`? 520 | 521 | Цикл `for` имеет все преимущества контроля выполнения и может быть прерван раньше, чем весь цикл будет пройден. 522 | `forEach` не может быть прерван и гарантированно пройдет по всем элементам коллекции. 523 | 524 |
525 | 526 | ### 34. 🔴 Можно ли объеденить код на ObjC и Swift в одном проекте? Если да, то как? 527 | 528 | Да, такая возможность присутствует. В первую очередь необходимо создать bridging header файл, который будет инклудить в себя все header файлы ObjC кода, которые вы планируете использовать в Swift коде. Все Swfit типы, которые планируется использовать внутри ObjC кода, необходимо маркировать `@objc` аттрибутом, или наследовать от NSObject класса. 529 | 530 |
531 | 532 | ### 35. 🔴 Можно ли объеденить код на C/C++ и Swift в одном проекте? Если да, то как? 533 | 534 | Да, такая возможность так же присутствует. Для начала необходимо выполнить все шаги, которые позволяют использовать ObjC код в Swift проекте. После чего использовать C/C++ код из ObjC кода, или переходить на так называемый ObjC++, смесь ObjC и C++, так как Swift не может напрямую работать с C/C++ кодом. 535 | 536 | > На данный момент Swift уже научился работать напрямую c C++, но я не изучал этот вопрос. 537 | 538 |
539 | 540 | ### 36. 🔴 Чем отличается вызов функции в Swift и отправка сообщения в ObjC? 541 | 542 | При вызове функции или метода в Swift функция, которую мы собираемся вызвать заранее определена и точно существует. Это может быть глобальная фукнция, метод экземпляра, или типа, функция может быть перегружена, но она точно есть и определена. Swift так работает в силу того, что является жестко типизированным языком. 543 | ObjC не имеет фукнций или методов, зато имеет сообщения, или селекторы, при вызове которых ObjC runtime пытается найти вызываемый селектор у объекта, у которого вы пытаетесь его вызвать. Если селектор будет найден, он будет вызван. Если нет - ничего не произойдет. 544 | Главное различие данных подходов в том, что вызов функции в Swift определяется на этапе компиляции, в то время как вызов селектора в ObjC - на этапе выполнения. Это позволяет в ObjC определять селекторы, которые вызываются после того, как программа уже написана, просто динамически подгружая их, к примеру, через библиотеку. 545 | 546 |
547 | 548 | ### 37. 🔴 Что такое `conditional conformance`? Как его реализовать и для чего используют? 549 | 550 | conditional conformance - это механизм языка Swift, который позволяет реализовать протокол generic типом при соблюдении тех или иных условий. 551 | 552 | ```swift 553 | protocol Loggable { 554 | func log() 555 | } 556 | 557 | extension Loggable { 558 | func log() { 559 | print(self) 560 | } 561 | } 562 | 563 | extension Array: Loggable where Element: Loggable {} 564 | extension Int: Loggable {} 565 | 566 | [1, 2, 3, 4].log() // prints [1, 2, 3, 4] 567 | ``` 568 | 569 |
570 | 571 | ### 38. 🟡 Что такое `async/await`? Что такое `Task`? Что такое `actor`? 572 | 573 | `async` и `await` - это два ключевых слова, которые работают в паре и позволяют выполнять код асинхронно. 574 | `async` - указывается в объявлении функции или метода и указывает, что данная функция или метод могут быть приостановлены для ожидания выполнения асинхронной операции. 575 | `await` - пишется перед вызовом любой функции или метода, которые имеют ключевое слово `async` в объявлении и являются возможной точкой приостановления для ожидания выполнения асинхронной операции. 576 | `Task` - тип, который представлят собой асинхронную задачу. Используется для перехода из синхронной среды в асинхронную. `async` функции и методы можно вызвать только внутри `Task` или из `async` функций или методов. 577 | `actor` - недавно появившаяся структура данных, которая очень похожа на `class`, но имеет ряд отличий. Во-первых, `actor` не может быть унаследован или наследовать другой тип. Во-вторых, `actor` гарантирует безопасность доступа к своим полям и вызова своих методов. Это называется изолированное состояние. Чтение/запись/вызов методов `actor` возможно только в асинхронной среде, за исключением тех полей и методов, которые имеют аттрибут `nonisolated`. 578 | 579 | ```swift 580 | func doSomeVeryLongStuff() async { 581 | ... 582 | } 583 | 584 | Task { 585 | await doSomeVeryLongStuff() 586 | } 587 | ``` 588 | 589 |
590 | 591 | ### 39. 🟡 Что такое `async let`? Чем это отличается от обычной `async/await` связки? 592 | 593 | `async let` позволяет создать `Promise`/`Future`. При объявлении такой константы, асинхронный вызов начинает исполняться, но текущий потом не прерывается. Получить данные из `async let` константы возможно только при помощи `await`. 594 | 595 | ```swift 596 | func doSomeVeryLongStuff() async -> Bool { 597 | // Do work ... 598 | return result 599 | } 600 | 601 | func doSomeMoreVeryLongStuff() async { 602 | async let result = doSomeVeryLongStuff() // await не употребляется, поток продолжает свое выполнение параллельно с doSomeVeryLongStuff 603 | ... 604 | if await result { // await употребляется при обрашении. Если значнение result все еще не появилось, поток будет приостановлен. Именно поэтому тут нужен await 605 | ... 606 | } 607 | } 608 | ``` 609 | 610 |
611 | 612 | ### 40. 🟡 Что такое `AsyncStream`? Зачем он нужен? 613 | 614 | `AsyncStream` - асинхронная последовательность элементов. По своей сути `AsyncStream` - это `Publisher` из `Combine`, который какое-то время или бесконечно генерирует новые значние определенного типа. Swift имеет специальный механизм для работы с `AsyncStream`. 615 | 616 | ```swift 617 | let stream = AsyncStream { ... } 618 | for await value in stream { // Похоже на обычный for loop, но с применением await. Если поток бесконечен, данный цикт никогда не будет завершен. 619 | print(value) 620 | } 621 | ``` 622 | 623 | > На плечи программиста всегда ложится задача вызвать Task.isCancelled или Task.checkCancellation() внутри тела асинхронного цикла. Если Task, в котором объявлен такой цикл будет отменен, цикл автоматически об этом не узнает и мы всегда должны проверять это вручную. 624 | 625 |
626 | 627 | ### 41. 🔴 Что такое `swizzling`? В чем его преимущества/недостатки? 628 | 629 | swizzling - это механизм ObjC Runtime, который позволяет заменить реализацию одного селектора на другую. Так как определение вызова селектора происходит в процессе исполнения программы, подменить один селектор другим представляется возможным. 630 | Чаще всего swizzling используется для того, чтобы переписать некоторые селекторы встроенных типов, добавляя туда свой функционал, к примеру, отправку аналитики из UIViewController. 631 | Несмотря на то, что swizzling не нарушает никакие гайдлайны, использование swizzling необходимо тщательно обдумать, так как вычислить имеет ли он место быть или нет, не зная заранее ответ на этот вопрос, может быть не просто. 632 | 633 | > Лично я считаю, что это стоило бы в принципе запретить. Вместо того, чтобы просто использовать наследование, или протокол, мы просто подменяем селекторы "по-тихому". Это очень тяжело дебажить. Это должно быть отображено в документации (ха-ха). Каждый новый разработчик должен быть в курсе того, что swizzling имеет место быть и так далее. Слишком много проблем ради пяти минут лени. 634 | 635 |
636 | 637 | ### 42. 🔴 Что такое условная компиляция? Для чего она используется? 638 | 639 | Условная компиляция - механизм языка, который позволяет компилировать участки кода лишь только в том случае, если какое-то условие выполнено. Это достаточно низкоуровневый механизм, который использует флаги компиляции а так же определенные пользователем флаги для определения выполнения условия. 640 | Существует так же ряд специальных деректив, которые расширяют возможности условной компиляции. К примеру, есть возможность определить под какую систему код компилируется в данный момент, происходит ли сейчас выполнение на настоящем устройстве, или на симуляторе, можем ли мы заимпортить тот или иной модуль и так далее. 641 | 642 |
643 | 644 | ## Паттерны 645 | 646 | ### 1. 🟢 Как расшифровывается `SOLID`? 647 | 648 | S - single responsibility. Каждый элемент программы должен выполнять только одну роль. 649 | O - open-closed. Элементы программы должны быть открыты к расширению, но закрыты к модификации. 650 | L - Liskov substitution. Элементы программы, работающие с базовыми классами или протоколами, должны так же работать и с наследниками или реализаторами протокола. 651 | I - Interface segregation. Множество специализированных интерфейсов лучше, чем один большой на все сразу. 652 | D - Dependency inversion. Строить зависимости необходимо на интерфейсах, нежеле на конкретных типах. 653 | 654 | > Это еще один очень любимый и никому не нужный вопрос, ответ на который, по сути, гуглится ровно за 5 минут до собеседования. 655 | > Вы должны знать принципы SOLID и использовать их там, где это необходимо, но знать наизусть слово в слово определние каждого термина - это маразм. 656 | 657 |
658 | 659 | ### 2. 🟢 Какие паттерны используются в `iOS`? 660 | 661 | В iOS три самых распространенных паттерна - это `singleton`, `delegate` и `observer`. С недавних пор к ним присоединились `publisher` и `actor`. 662 | 663 |
664 | 665 | ### 3. 🟢 Что такое `Singleton`? Что с ним не так? 666 | 667 | `Singleton` - пораждающий паттерн, который гарантирует единственность экземпляра конкретного типа. Основная проблема `Singleton` - практически полная невозможность контролировать доступ и модификацию его состояния, так как он доступен всегда из всего кода. 668 | 669 |
670 | 671 | ### 4. 🟢 Как реализовать `Singleton` в Swift? 672 | 673 | Еще один вопрос, когда лучше просто написать сразу код. 674 | 675 | ```swift 676 | final class Singleton { 677 | static let shared = Singleton() 678 | 679 | private init() {} 680 | } 681 | ``` 682 | 683 | > Я видел синглтоны, которые реализовывали через `struct`. В целом это допустимо, но накладывает целый ряд дополнительных трудностей в использовании такого синглтона. 684 | 685 |
686 | 687 | ### 5. 🟢 Что такое `Delegate`? Как его использовать? 688 | 689 | `Delegate` - поведенческий паттерн, который перекладывает часть реализации на другой объект. Делегаты используются в iOS сплошь и рядом в основном для того, чтобы уточнить часть информации, которая зависит от вашего кода и встроить в уже готовую реализацию используемых компонентов. 690 | 691 | > Примеры: `UITableViewDataSource` и `UITableViewDelegate` 692 | 693 |
694 | 695 | ### 6. 🟢 Что такое `Observer`? Как его использовать? 696 | 697 | `Observer` - поведенческий паттерн, который позволяет наладить механизм подписки на события нескольким объектам и реагировать на эти события. 698 | 699 | > Пример: `NotificationCenter`. 700 | 701 |
702 | 703 | ### 7. 🟢 Назовите все парттерны, которые вы знаете. Перечислите те, которые вы использовали на практике. 704 | 705 | В принципе сейчас, наконец-то, народ начал по-немного отходить от того, что знание всех паттернов в мире показывает хоть что-то, кроме того, что у вас хорошая память. Основные паттерны, приведенные выше, знать надо, потому что они используются абсолютно везде в iOS, но что до остальных - все весьма по желанию и опционально. 706 | 707 | > И да, все вопросы про паттерны как начинаются, так и заканчиваются на джунах, дальше это уже никому не интересно. 708 | 709 |
710 | 711 | ## UI 712 | 713 | ### 1. 🟢 Назовите все состояния, в которых может находиться iOS приложение (Application life cycle). Назовите примеры, когда может наступить каждое из состояний. 714 | 715 | iOS приложение может находится в одном из нескольких состояний: 716 | 717 | * Not running - приложение не запущено. 718 | * Foreground inactive - приложение находится на экране, но не является first responder. Такое может произойти, например, когда ваше приложение перекрывает UI телефонного звонка. 719 | * Foreground active - ваше приложение находится на экране и является first responder. 720 | * Background - ваше приложение свернуто и не находится на экране, однако оно все еще работает и получает обновления от системы. 721 | * Suspended - ваше приложение свернуто, не находится на экране и больше не получает обновления от системы. 722 | 723 | > Вопрос встречается часто, на практике данные знания применяются очень редко. 724 | 725 |
726 | 727 | ### 2. 🟢 Какие из этих состояний вы используете чаще всего в работе? 728 | 729 | Вопрос довольно глупый, но он все равно бывает. В 99.9999% случаев вы работаете с Foreground Active состоянием. 730 | 731 |
732 | 733 | ### 3. 🟢 Что такое `Storyboard`? Что такое `Xib`? Чем отличаются `Xib` и `Nib`? Для чего их используют? 734 | 735 | `Storyboard`, `Xib` и `Nib` - это, по своей сути, одно и тоде - `XML` файл, который описывает UI приложения. Формат данного файла не имеет документации и данные файлы не предполагают редактирование за пределами `Interface Builder`. 736 | `Xib` и `Nib` не отличаются вообще ничем, это два названия для одного и тоже термина, на смену `Nib` пришел `Xib`. `Xib` описывает UI отдельно взятой `UIView` или нескольких `UIView`. 737 | `Storyboard` отличается от `Xib` тем, что имеет ряд дополнительных возможностей, так как описывает UI не `UIView`, а одного или нескольких `UIViewController`. В связи с этим `Storyboard` может так же определять взаимодействия и переходы между разными `UIViewController`. 738 | 739 | > Не уточнял последние тренды, но на практике уже очень давно не видел в проектах Interface Builder. А сейчас так и вообще все больше вижу SwiftUI. 740 | 741 |
742 | 743 | ### 4. 🟢 Какие UI фреймворки доступны в iOS? Чем они отличаются? 744 | 745 | Для построения UI iOS может использовать два фреймворка: `UIKit` или `SwiftUI`. 746 | Данных два фреймворка отличаются очень многим, в деталях это расписывать очень долго. Если вкратце, то `UIKit` существует испокон веков и именно на нем строится весь UI iOS приложения, там происходит его реальная имплементация. 747 | `SwiftUI`, в свою очередь, новый фреймворк, который не столько реализует UI (пока что), как описывает его, а конкретная реализация падает на плечи других фреймворков, в зависимости от того, на какой платформе данный код будет исполняться. На iOS все так или иначе опускается до `UIKit`. 748 | 749 |
750 | 751 | ### 5. 🟢 Что такое UIKit? 752 | 753 | `UIKit` - это UI фреймворк, который хранит в себе огромную массу функционала и возможностей для построения UI всего вашего приложения. Все, что будет отображено на экране и взаимодействовать с пользователем через экран, находится в `UIKit`. 754 | 755 |
756 | 757 | ### 6. 🟢 Что такое AutoLayout? Для чего его используют? 758 | 759 | AutoLayout - это система внутри `UIKit`, которая отвечает за размещение и размеры элементов на экране приложения. AutoLayout работает через constraints - элементы, которые являются частью уравнения, которое AutoLayout решает, когда размещает и задает размер ваших UI элементов на экране. 760 | 761 |
762 | 763 | ### 7. 🟢 Какое минимальное количество constraints надо задать, чтобы определить положение `UIView` на экране? 764 | 765 | Есть несколько вариантов ответа на этот вопрос: 766 | 767 | * 2 constraints, одна по вертикали, а вторая по горизонтали, если `intrinsicContentSize` вьюхи определен. 768 | * 3 constraints, если `intrinsicContentSize` вьюхи определен только по одной оси. Тогда необходим дополнительный constraint по оси, по которой `intrinsicContentSize` не определен. 769 | * 4 constraints, по две по вертикали и горизонтали, если `intrinsicContentSize` вьюхи не определен. 770 | 771 |
772 | 773 | ### 8. 🟢 Назовите основные аттрибуты constraint и что каждый из них означает 774 | 775 | constraint имеет следующие аттрибуты: 776 | 777 | * `firstItem` - первый якорь элемента, к которому относится данный constraint. 778 | * `secondItem` - второй якорь элемента, к которому относится данный constraint. Элемент может быть другим или тем же. Якорь может быть nil. 779 | * `constant` - константа constraint. 780 | * `multiplier` - множитель константы или значения якоря элемента. 781 | * `relation` - отношение между якорями. Может быть `equalTo`, `greaterThanOrEqualTo`, lessThanOrEqualTo`. 782 | * `priority` - приоритет constraint. Находится в диапазоне от 0 до 1000. 783 | 784 | > Забавный факт: только `constant` может быть изменен после создания `constraint`. 785 | 786 |
787 | 788 | ### 9. 🟢 Что такое `contentHuggingPriority` и `contentCompressionResistancePriority`? Как их использовать и для чего? 789 | 790 | `contentHuggingPriority` - это приоритет, который говорит насколько вероятно, что `UIView` станет больше своего необходимого размера. 791 | `contentCompressionResistancePriority` - это приоритет, который говорит насколько вероятно, что `UIView` станет меньше своего необходимого размера. 792 | Данный приоритеты используются вместе с приоритетами constraint для решения неопределенности, при которой две `UIView` не могут определить свой размер. 793 | 794 |
795 | 796 | ### 10. 🟢 Что такое `UIStackView`? В чем его преимущества/недостатки? 797 | 798 | `UIStackView` - это `UIView`, которая не имеет своего графического представления и используется исключительно для расположения своих `subViews` по вертикали или по горизонтали. 799 | Преимущества `UIStackView` очевидны - меньше ручной настройки UI для достижения тривиальных задач. Недостатки вытекают отсюда же: если необходимо сделать немного более сложный UI, чем просто расположить элементы один за другим, `UIStackView` может создать больше проблем, чем решить. 800 | 801 |
802 | 803 | ### 11. 🟢 Жизненный цикл `UIViewController`. Назовите все методы-обработчики жизненного цикла и когда каждый из них вызывается. 804 | 805 | У `UIViewController` есть следующие методы-обработчики жизненного цикла: 806 | 807 | * `viewDidLoad` - вызывается всего один раз для каждого `UIViewController` в течени жизненного цикла. Сигнализирует о том, что вью была загружена и теперь может быть использована. 808 | * `viewWillAppear` - вызывается перед тем, как `UIViewController` будет показан на экране. Может быть вызван более одного раза за жизненный цикл. 809 | * `viewIsAppearing` - вызывается в момент, как UIViewController уже добавлен в иерархию и начинает показываться на экране. Может быть вызван более одного раза за жизненный цикл. 810 | * `viewDidAppear` - вызывается после того, как `UIViewController` был показан на экране и анимация его представления завершилась. Может быть вызван более одного раза за жизненный цикл. 811 | * `viewWillDisappear` - вызывается перед тем, как `UIViewController` будет убран с экрана. Может быть вызван более одного раза за жизненный цикл. 812 | * `viewDidDisappear` - вызывается после того, как `UIViewController` был убран с экрана и анимация его исчезновения завершилась. Может быть вызван более одного раза за жизненный цикл. 813 | 814 |
815 | 816 | ### 12. 🟢 Чем отличаются `frame` и `bounds`? 817 | 818 | `frame` - это прямоугольник, который представляет положение и размер `UIView` в системе координат ее `superView`. 819 | `bounds` - это прямоугольник, который представляет положение и размер `UIView` в системе координат этой же `UIView`. `origin` `bounds` всегда находится в координате (0, 0). 820 | 821 |
822 | 823 | ### 13. 🟢 Что такое `UISegue`? Как они обрабатываются? Какие есть альтернативы и в чем преимущества/недостатки каждого из них? 824 | 825 | `UISegue` - это встроенный тип, который отвечает за переход между несколькими `UIViewController`, объявленный в `Storyboard`. 826 | Чтобы обработать `UISegue`, необходимо перегрузить метод `prepare`. 827 | Альтернативой использования `UISegue` будет создание и презентация `UIViewController` вручную в том месте, где необходимо выполнить переход с одного `UIViewController` на другой. Как правило `UISegue` не используют в силу того, что они всецело опираются на `identifier`, который является просто строкой из-за чего работать с ним не очень удобно. 828 | 829 |
830 | 831 | ### 14. 🟢 `UINavigationController` - что это, для чего используется и как реализован? 832 | 833 | `UINavigationController` - это `UIViewController`, который является контейнером для других `UIViewController` и осуществляет навигацию между ними. `UINavigationController` имеет `UINavigationBar`, который показывается в верхней части экрана, а так же имеет стандрартные анимации перехода между `UIViewController`-ами, переход между которыми происходит в данный момент. Является одним из самый важных и основных компонентов UI. 834 | 835 |
836 | 837 | ### 15. 🟢 `UITabController` - что это, для чего используется и как реализован? 838 | 839 | `UITabController` - это `UIViewController`, который является контейнером для других `UIViewController` и осуществляет переход между ними посредстом табов. `UITabController` показывает таб бар в нижней части экрана, где у каждой табы может быть своя иконка и название. Является одним из основных компонентов UI, однако используется не всегда. 840 | Начиная с iPadOS 18 UITabController находится в верхней части экрана для `regular size class` и может быть представлен как `sidebar`. 841 | 842 |
843 | 844 | ### 16. 🟢 Что такое `UITableView`? Для чего его использовать и что необходимо сделать, чтобы его использовать? 845 | 846 | `UITableView` - `UIview`, которая представляет собой вертикальный список, каждый элемент которого - это ячейка списка. `UITableView` - это один из наиболее часто используюемых компонентов при построении UI приложения и его можно встретить практически в каждом приложении. 847 | 848 | Чтобы использовать `UITableView`, необходимо реализовать протокол `UITableViewDataSource`. В этом случае вы можете отобразить данные, но не сможете с ними взаимодействовать. Если же необходимо обрабатывать пользовательское взаимодействие с таблицей, необходимо так же реализовать протокол `UITableViewDelegate`. 849 | У `UITableViewDataSource` есть альтернатива - `UITableViewDiffableDataSource`. В отличии от `UITableViewDataSource` это не протокол, а конкретный тип, который реализовывает более современный подход к работе с таблицами. 850 | 851 | > `UITableViewDiffableDataSource` в реальном коде стала встречаться все чаще и чаще, так что я настоятельно рекомендую переходить на этот подъод, если вы все еще сидите на старом. 852 | 853 |
854 | 855 | ### 17. 🟢 Что такое `UICollectionView`? Для чего его использовать и что необходимо сделать, чтобы его использовать? 856 | 857 | `UICollectionView` - `UIview`, которая представляет собой коллекцию, состоящую из ячеек. Визуальное представление `UICollectionView` зависит от его `collectionViewLayout` и может быть абсолютно любым. Самый частый случай - это вертикальная или горизонтальная сетка элементов. Так же как и `UITableView` является одним из наиболее часто используюемых компонентов при построении UI приложения. 858 | 859 | Чтобы использовать `UICollectionView`, необходимо реализовать протокол `UICollectionViewDataSource`. В этом случае вы можете отобразить данные, но не сможете с ними взаимодействовать. Если же необходимо обрабатывать пользовательское взаимодействие с коллекцией, необходимо так же реализовать протокол `UICollectionViewDelegate`. 860 | У `UICollectionViewDataSource` есть альтернатива - `UICollectionViewDiffableDataSource`. В отличии от `UICollectionViewDataSource` это не протокол, а конкретный тип, который реализовывает более современный подход к работе с коллекциями. 861 | Так же, если вы хотите использовать `collectionViewLayout` отличный от `UICollectionViewFlowLayout`, его так же необходимо отдельно создать, настроить и указать коллекции. 862 | 863 | > `UICollectionViewDiffableDataSource` в реальном коде стала встречаться все чаще и чаще, так что я настоятельно рекомендую переходить на этот подъод, если вы все еще сидите на старом. 864 | 865 |
866 | 867 | ### 18. 🟢 В чем отличие `UICollectionView` и `UITableView`? 868 | 869 | `UITableView` способна отображать свои элементы исключительно как вертикальный список, в то время, как элементы коллекции могут отображаться в абсолютно произвольной форме. Современные нововведения в `UICollectionView` позволяют полностью перестать использовать `UITableView`. 870 | 871 |
872 | 873 | ### 19. 🟢 Что такое `GestureRecognizer`? Какие они бывают? 874 | 875 | `GestureRecognizer` - это встроенный тип, позволяющий обрабатывать различные жесты пользователя. Они бывают следуюших типов: 876 | 877 | * `UITapGestureRecognizer` - обрабатывает короткое нажатие. 878 | * `UIPinchGestureRecognizer` - обрабатывает двухпальцевый жест увеличения и уменьшения. 879 | * `UIRotationGestureRecognizer` - обрабатывает двухпальцевый жест поворота. 880 | * `UISwipeGestureRecognizer` - обрабатывает быстрый смах по экрану. 881 | * `UIPanGestureRecognizer` - обрабатывает жест перемещения пальца по экрану. 882 | * `UIScreenEdgePanGestureRecognizer` - обрабатывает жест перемещения пальца от края экрана. 883 | * `UILongPressGestureRecognizer` - обрабатывает жест длинного нажатия на экран. 884 | * `UIHoverGestureRecognizer` - обрабатывает жест наведения курсора на элемент UI. Доступен только на iPadOS. 885 | 886 |
887 | 888 | ### 20. 🟢 Что такое LaunchScreen.storyboard? Можно ли динамически менять его элементы или поставить ему класс-обработчик? Почему? 889 | 890 | LaunchScreen.storyboard - это специальный storyboard, который показывается в момент запуска приложения. Содержимое данного storyboard нельзя динамически настраивать так же, как и `UIViewController` не может иметь класс-обработчик, так как LaunchScreen.storyboard показывается до того, как метод `application(_:didFinishLaunchingWithOptions:)` будет вызван. 891 | 892 |
893 | 894 | ### 21. 🟡 Что такое size class? Какие они бывают? Для чего их используют? 895 | 896 | Size class - это параметр, указывающий на то, в каком окружении в данный момент выполняется наше приложение. Есть два значения size class - по-вертикали и по-горизонтали. Комбинация этих значений может указать нам на диапазон устройст и состояний устройств, в которых мы сейчас исполняемся. Используется для построения различного UI в зависимости от доступного пространства на экране. 897 | Size class может быть одним из следующих значений: 898 | 899 | * compact 900 | * regular 901 | * unspecified 902 | 903 | Как определить девайс и положение девайса по size class: 904 | 905 | * [Width: Compact, Height: Regular]: 906 | - все айфоны в портретном режиме; 907 | - все айпэды в режиме overlay или splitView в соотношении 1/3 в ландшафтном или портретном режиме; 908 | - все айпэды, кроме 12.9", в режиме splitView в соотношении 1/2 в ландшафтном режиме. 909 | * [Width: Compact, Height: Compact]: 910 | - все айфоны в ландшафтном режиме, кроме Plus/Pro Max айфонов. 911 | * [Width: Regular, Height: Compact]: 912 | Plus/Pro Max айфоны в ландшафтном режиме. 913 | * [Width: Regular, Height: Regular]: 914 | - все айпэды в полноэкранном режиме; 915 | - 12.9" айпэды в режиме splitView в соотношении 1/2 в ландшафтном режиме. 916 | 917 | > Знать наизусть какие девайсы принадлежат какой комбинации не обязательно, достаточно понимать, какая комбинация будет встречаться в каком случае чаще всего. 918 | 919 |
920 | 921 | ### 22. 🟡 Как построить UI в коде? Какие преимущества/недостатки у данного подхода? 922 | 923 | Для того, чтобы построить UI в коде, необходимо всю работу Interface Builder-а взять на себя. А именно, создать экземпляры необходимых UIView, настроить их нужным образом, добавить во view hierarchy и задать между ними constraints. 924 | Преимущества данного подхода в том, что, во-первых, вы больше не связываетесь с Interface Builder. Больше не может случится ситуация, при которой в файле IB случилась непоправимая ошибка, в результате чего Xcode больше не может отрендерить UI в принципе и вам надо вручную искать ошибку в сгенерированном недокументированном файле. Во-вторых, мерж конфликты решать в коде значительно проще, чем в IB файлах. 925 | Недостатки вытекают из достоинств: слишком много кода, который просто настраивает UI, наглядно не видно, что именно и как настроено, работать с size class становится немного сложнее. 926 | 927 | > Лично я был одно время горячим фаном UI из кода, но чем больше проходило времени, тем больше я понимал, что сверстать какую-нибудь маленькую ячейку быстрее и проще в IB, а вот сливать все в кучу в каком-нибудь сложном ViewController все же лучше руками, так надежнее. В результате сейчас я стараюсь комбинировать два этих подхода. 928 | > Обновленный комментарий: в текущих реалиях я предпочитаю в принципе не связываться с UIKit, когда это возможно и делаю все на SwiftUI, который при необходимости потом встраиваю в UIKit. 929 | 930 |
931 | 932 | ### 23. 🟡 В чем разница между `CALayer` и `UIView`? Для чего нужен `CALayer`? 933 | 934 | `CALayer` является компонентом `CoreGraphics` - низкоуровнего API, который непосредственно занимается рендером и анимациями. `CALyaer` является наследником `CGLayer`. `UIView` является контейнером для `CALayer` и у каждой `UIView` есть как минимум один `CALayer`, как у каждого `UIViewController` есть как минимум один `UIView`. 935 | 936 |
937 | 938 | ### 24. 🟡 Как можно реализовать кастомную анимацию перехода между двумя экранами? 939 | 940 | Для этого необходимо реализовать протокол `UIViewControllerAnimatedTransitioning`, затем задать значение custom в поле `modalPresentationStyle`. Значение полю `transitioningDelegate` присвоить объект, который реализовал `UIViewControllerAnimatedTransitioning`. Все данные поля необходимо присваивать объекту `UIViewController` с которого необходимо реализовать кастомный переход. 941 | 942 |
943 | 944 | ### 25. 🟡 `UISplitViewController` - что это, для чего используется и как реализован? Какие недавние изменения в нем появились? 945 | 946 | `UISplitViewController` - это `UIViewController`, который является контейнером для других `UIViewController`. `UISplitViewController` располагает свои `viewControllers` друг рядом с другом по горизонтали. Первая колонка по умолчанию будет значительно уже второй. Данное расположение доступно только для девайсов, которые имеют `regular size class` по горизонтали. При значении `compact size class` по горизонтали `UISplitViewController` превращается в обычный `UINavigationController`. 947 | С недавних пор `UISplitViewController` был обновлен. Ему полностью переписали API, добавили возможность сделать три колонки, а так же сделать полноценно отдельный `UIViewController` для девайсов со значением `compact size class` по горизонтали. 948 | 949 |
950 | 951 | ### 26. 🟡 В чем разница между `layoutIfNeeded()`, `setNeedsLayout()` и `layoutSubviews()`? 952 | 953 | `layoutIfNeeded()` - метод `UIView`, который инициирует полный перерасчет всего UI данной `UIView` и всех ее subViews, если текущий UI не актуален. 954 | `setNeedsLayout()` - метод `UIView`, указывающий UIView, что текущее отображение UI данной `UIview` более не актуально и должно быть пересчитано. 955 | `layoutSubviews()` - метод `UIView`, который инициирует полный перерасчет всего UI данной `UIView` и всех ее subViews. В отличии от `layoutIfNeeded()` не проверяет текущий UI на актуальность. 956 | 957 |
958 | 959 | ### 27. 🟡 Что такое UIResponder? Для чего он используется? Как происходит обработка событий UIResponder? 960 | 961 | UIResponder - тип UIKit, который отвечает за обработку всех событий пользователя. Обработка событий `UIResponder` происходит по цепочке ответственности. Если данный `UIResponder` не может обработать то или иное событие, он пробрасывает событие далее своим дочерним `UIResponder`. Так событие опускается до тех пор, пока не будет обработано, или, пока не закончатся `UIResponder`-ы. 962 | 963 |
964 | 965 | ### 28. 🟡 Какие UI операции можно делать не на главном потоке? 966 | 967 | Вопрос с подвохом. Если мы говорим об операциях, которые непосредственно взаимодействуют с UI нашего приложения, который находится на экране или во вью стеке, то все подобные операции обязаны выполняться только на главном потоке. Без исключний. 968 | Если же мы говорим о UI операциях в целом, то все операции, которые не взаимодействуют с UI во вью стеке, можно выполнять где-угодно. Другими словами, получить данные картинки и создать `UIImage` можно на любом потоке, но присвоить `UIImageView` поле `image` можно только на главном потоке, если данная `UIImageView` находится во вью стеке. 969 | 970 |
971 | 972 | ### 29. 🟡 Что такое UIScene? Для чего их используют? 973 | 974 | `UIScene` - тип `UIKit`, который появился в iOS 13. `UIScene` отвечает за хранение `UIWindow` приложения. `UIScene` имеет смысл только на iPadOS. Данный тип позволяет осуществлять запуск более одного экземпляра приложения одновременно. Так же, благодаря `UIScene` на iPadOS работает мультиоконный режим, при котором несколько приложений могут находится на экране одновременно. 975 | 976 |
977 | 978 | ### 30. 🟡 Сколько LaunchScreen сторибордов может быть в приложении? Если более одного, то как система определяет, какой использовать сейчас? 979 | 980 | По умолчанию, при создании любого iOS приложения, Xcode сгенерирует один LaunchScreen.storyboard, который будет использовать при любом запуске приложения. Однако, вы можете создать и другие подобные storyboard-ы. При реализации URL схем и Push notification, вы можете указать какой конкретно LaunchScreen.storyboard вы хотели бы использовать, если при обработке схемы или уведомления приложение будет запускаться с нуля. 981 | 982 | > Никогда не видел, чтобы это хоть кто-то испольховал в реальном проекте. Так же, хотел внести поправку: при создании новых проектов на SwiftUI, LaunchScreen.storyboard больше не создается автоматически. 983 | 984 |
985 | 986 | ### 31. 🔴 Что такое `CADisplayLink`? Для чего его используют? 987 | 988 | `CADisplayLink` - тип фреймворка UIKit, который отвечает за синхронизацию с тактом рендера. `CADisplayLink` используется для того, чтобы выполнять действия ровно каждый кадр. 989 | 990 |
991 | 992 | ### 32. 🟡 Что такое `SwiftUI`? 993 | 994 | `SwiftUI` - новый фреймворк для UI, который не столько строит и рендерит сам UI, сколько описывает его и опирается на реальный функционал других API, в зависимости от того, на какой платформе будет исполняться код, написанный с помощью `SwiftUI`. 995 | Данный фреймворк все еще довольно молод и не позволяет воссоздать абсолютно все, что можно сделать на `UIKit`/`AppKit`, однако `SwiftUI` позволяет внедрять `UIKit`/`AppKit` код в `SwiftUI` код и наоборот. 996 | 997 | > С каждым новым релизом SwiftUI становится все мощнее и сейчас уже практически невозможно найти вакансию, где он бы не требовался. Если вы все еще не начали работать/изучать SwiftUI, я вам настоятельно рекомендую начать. 998 | 999 |
1000 | 1001 | ### 33. 🟡 Что такое `View`? Для чего он используется? 1002 | 1003 | `View` - основной протокол фреймворка `SwiftUI`. Все, что отображается на экране, будь то целый экран, или его элемент, должны реализовать данный протокол. `body` параметр `View` является `@ViewBuilder`. Начиная с Swift 6.0, протокол `View` помечен атрибутом `@MainActor`. 1004 | 1005 |
1006 | 1007 | ### 34. 🟡 Что такое `ViewModifier`? Для чего он используется? 1008 | 1009 | `ViewModifier` - второй по значимости протокол в `SwiftUI`. С его помощью мы можем модифицировать уже созданную `View`, меняя текущие параметры или добавляя новые. 1010 | 1011 |
1012 | 1013 | ### 35. 🟡 Назовите основные компоненты SwiftUI, которые вы используете. 1014 | 1015 | В принципе назвать вы можете все, что угодно, но на месте интервьюера я бы ожидал как минимум следующие: 1016 | 1017 | * `H/V/ZStack` - горизонтальный, вертикальный стеки и стек в глубину. Располагают элементы по-горизонтали/по-вертикали/один поверх другого. 1018 | * `Text` - местный `UILabel`. Используется для отображения текста. 1019 | * `Button` - кнопка. Вызывает `action` по нажатию. Может иметь системный дизайн или кастомный. 1020 | * `Image` - Изображение. Отображает любую картинку, включая SF Symbols. 1021 | * `Color` - Цвет. Может использоваться как `View`, также используется сплошь и рядом для модификации разных компонентов. 1022 | * `Toggle` - Переключатель, местный UISwitch. По-умолчанию имеет стиль из системы, но может быть кастомизирован. 1023 | * `Picker` - Выбиралочка. Может выглядеть практически как-угодно. Выбор элемента осуществляется по `tag` viewModifier. 1024 | * `Menu` - Кнопка, основной action которой - показать меню. 1025 | * `ScrollView` - Обычный, системный скролл, по-умолчанию только с вертикальной осью, занимает все досупное ему пространство. 1026 | * `List` - местный UITableView. Вертикальный список, все элементы которого будут его ячейками. Стиль кастомизируется, но не на 100% 1027 | * `NavigationStack` - Стэк навигации. Добавляет NavigationBar в верх экрана, позволяет производить переходы между экранами. 1028 | 1029 |
1030 | 1031 | ### 36... Данная секция будет дополняться, предложения приветствуются. 1032 | 1033 | ## Хранение данных 1034 | 1035 | ### 1. 🟢 Какие виды persistency вы знаете в iOS? 1036 | 1037 | Из коробки в iOS нам доступны следующие хранилища: `UserDefaults`, `CoreData`, `KeyChain` и запись в файл. Совсем недавно этот списо пополнил SwiftData. 1038 | 1039 |
1040 | 1041 | ### 2. 🟢 Что такое `plist` файл? Для чего он использутеся? Какие типы данных можно хранить в `plist` файле? 1042 | 1043 | `plist` файл в iOS - это файл, который содержит информацию в виде (ключ, значение), как и `Dictionary`. Используется для различных целей, как правило, содержит набор настроек или информации, специфической для вашего приложения. 1044 | 1045 | > Пример: `Info.plist` 1046 | 1047 |
1048 | 1049 | ### 3. 🟢 Что такое `UserDefaults`? Для чего они используются? 1050 | 1051 | `UserDefaults` - одно из локальных хранилищ, которое хранит информацию в виде `plist` файла. Данное хранилище не шифруется, следовательно не предназначено для хранения чувствительной информации. Так же данное хранилище не является базой данных и не подходит для хранения больших массивов данных, сложных связей между моделями и не имеет возможности составлять сложные запросы, как СУБД. Как правило `UserDefaults` используют для хранения настроек приложения или флагов, которые даже при утечки не несут никакой угрозы бизнесу или пользователям приложения. 1052 | 1053 |
1054 | 1055 | ### 4. 🟡 Что такое CoreData? Когда и для чего ее используют? 1056 | 1057 | `CoreData` — это фреймворк от Apple для управления графом объектов и сохранения данных. Его используют для хранения, извлечения и обработки данных внутри приложения, чтобы работать с локальной базой данных. 1058 | 1059 |
1060 | 1061 | ### 5. 🟡 Какие альтернативы CoreData вы знаете и в чем их преимущества/недостатки? 1062 | 1063 | * Realm: Простой API, быстрая работа с большим количеством данных, но требует сторонней библиотеки. 1064 | * SQLite: Гибкая реляционная база данных, но требует больше ручного кода. 1065 | * UserDefaults: Прост в использовании, но подходит только для небольших настроек и данных. 1066 | * SwiftData: Новый член данного семейства, написанный на Swift и всецело полагающийся на макросы. Очень глубоко внедрен в SwiftUI, по слухам глубоко под капотом построен поверх CoreData. 1067 | 1068 | > Я бы не рисковал пока что использовать SwiftData. Фреймворк слишком молод и требует доработок. 1069 | > По недавним новостям, Realm задепрекейтили, так что я бы на него не ставил тоже. 1070 | 1071 |
1072 | 1073 | ### 6. 🟡 Назовите основные элементы CoreData. 1074 | 1075 | * `NSManagedObjectModel`: Это объект, который содержит описание схемы данных. Он включает в себя все сущности (entities), их атрибуты и отношения (relationships) между ними. Фактически, это как план базы данных, который описывает структуру данных, которые будут храниться. 1076 | * `NSPersistentStoreCoordinator`: Это компонент, который управляет хранилищем данных (например, базой SQLite). Он отвечает за связывание модели данных с физическим местом хранения. NSPersistentStoreCoordinator позволяет вам подключать несколько хранилищ данных (например, одно для SQLite и другое для XML или бинарных данных). 1077 | * `NSManagedObjectContext`: Это основное место для работы с объектами в Core Data. `NSManagedObjectContext` отслеживает все изменения, которые вы делаете с данными, и отвечает за сохранение этих изменений в хранилище. Он действует как временное хранилище для данных во время работы приложения. 1078 | * `NSManagedObject`: Это класс, который представляет сущности (entities) из вашей модели данных. `NSManagedObject` — это объекты, которые содержат данные и находятся под управлением `NSManagedObjectContext`. Каждый экземпляр `NSManagedObject` представляет собой одну запись в базе данных. 1079 | * `NSPersistentContainer`: Это более новый элемент, который упрощает настройку `CoreData`. Он включает в себя весь стек `CoreData` (`NSManagedObjectModel`, `NSPersistentStoreCoordinator`, `NSManagedObjectContext`) и обеспечивает более простой способ конфигурирования и работы с `CoreData` в приложении. 1080 | 1081 |
1082 | 1083 | ### 7. 🟡 Где могут храниться данные из CoreData? 1084 | 1085 | Данные, которые вы сохраняете через `CoreData`, могут храниться в нескольких типах хранилищ: 1086 | 1087 | * SQLite: Наиболее распространенный формат, обеспечивающий реляционную базу данных на устройстве. 1088 | * Binary Store: Данные сохраняются в бинарном формате, что может быть быстрее для небольших объемов данных, но не подходит для больших или сложных структур. 1089 | * XML: Формат для простых данных, но медленный и неэффективный для больших объемов данных. 1090 | 1091 |
1092 | 1093 | ### 8. 🟡 Что такое NSPersistentStoreCoordinator? Для чего его используют? 1094 | 1095 | `NSPersistentStoreCoordinator` - это компонент `CoreData`, который управляет связью между объектной моделью данных и фактическим хранилищем данных (например, SQLite или бинарные файлы). Он отвечает за подключение к хранилищу данных, добавление новых хранилищ и управление операциями ввода-вывода для сохранения данных. 1096 | 1097 | Используется для: 1098 | * Управления одним или несколькими хранилищами данных. 1099 | * Обеспечения синхронизации между моделью данных и физическим хранилищем. 1100 | * Работы с несколькими источниками данных в одном приложении. 1101 | 1102 |
1103 | 1104 | ### 9. 🟡 Что такое NSManagedObjectContext? Для чего его используют? 1105 | 1106 | `NSManagedObjectContext` — это основной рабочий объект `CoreData`, который используется для управления объектами приложения. В нем создаются, удаляются и изменяются данные. Этот контекст отслеживает изменения и взаимодействует с `NSPersistentStoreCoordinator` для сохранения данных в хранилище. 1107 | 1108 | Используется для: 1109 | * Выполнения операций с объектами (создание, чтение, обновление, удаление). 1110 | * Синхронизации изменений с основным хранилищем (например, SQLite). 1111 | * Работы с объектами на разных потоках, обеспечивая корректную работу с данными в многопоточных приложениях. 1112 | 1113 |
1114 | 1115 | ### 10. 🟡 Что такое NSFetchRequest? Для чего его используют? 1116 | 1117 | `NSFetchRequest` — это запрос, который используется для извлечения данных из хранилища `CoreData`. Он позволяет задать условия, фильтры, сортировки и лимиты для извлекаемых данных. 1118 | 1119 | Используется для: 1120 | * Получения данных по критериям (например, все объекты определенного типа или объекты, удовлетворяющие условиям). 1121 | * Фильтрации данных по атрибутам (например, все записи, созданные в последний месяц). 1122 | * Упорядочивания данных (например, сортировка по дате или имени). 1123 | 1124 |
1125 | 1126 | ### 11. 🟡 Что такое NSFetchResultsController? Для чего его используют? 1127 | 1128 | `NSFetchedResultsController` — это объект, который отслеживает изменения в результатах запроса `CoreData` и автоматически уведомляет интерфейс об изменениях. Это особенно полезно при работе с таблицами (`UITableView` или `UICollectionView`), где данные могут динамически изменяться. 1129 | 1130 | Используется для: 1131 | * Автоматического обновления пользовательского интерфейса при изменении данных. 1132 | * Эффективной работы с большими объемами данных в таблицах. 1133 | * Упрощения работы с данными, освобождая разработчика от необходимости вручную обновлять интерфейс при изменении данных. 1134 | 1135 |
1136 | 1137 | ### 12. 🟡 Как работать с CoreData в многопоточной среде? 1138 | 1139 | Работа с `CoreData` в многопоточной среде требует использования отдельных `NSManagedObjectContext` для каждого потока. Каждый поток должен иметь собственный контекст, чтобы избежать конфликтов данных. 1140 | 1141 | 1. Создайте новый `NSManagedObjectContext` для каждого потока. 1142 | 2. Убедитесь, что каждый контекст связан с одним и тем же `NSPersistentStoreCoordinator` для синхронизации данных. 1143 | 3. Для синхронизации изменений между контекстами используйте нотификации или механизмы слияния данных (например, mergeChanges). 1144 | 1145 |
1146 | 1147 | ### 13. 🟡 Как реализовать чтение/запись файла в iOS? 1148 | 1149 | Для чтения и записи файлов в iOS можно использовать `FileManager` — встроенный класс для работы с файловой системой. Вот пример работы с файлами: 1150 | 1151 | **Запись файла:** 1152 | ```swift 1153 | let fileManager = FileManager.default 1154 | let filePath = fileManager.temporaryDirectory.appendingPathComponent("myFile.txt") 1155 | let text = "Hello, world!" 1156 | do { 1157 | try text.write(to: filePath, atomically: true, encoding: .utf8) 1158 | } catch { 1159 | print("Ошибка при записи файла: \(error)") 1160 | } 1161 | ``` 1162 | 1163 | **Чтение файла:** 1164 | ```swift 1165 | do { 1166 | let content = try String(contentsOf: filePath, encoding: .utf8) 1167 | print("Содержимое файла: \(content)") 1168 | } catch { 1169 | print("Ошибка при чтении файла: \(error)") 1170 | } 1171 | ``` 1172 | 1173 |
1174 | 1175 | ### 14. 🟡 Что такое KeyChain? Для чего он используется? 1176 | 1177 | `Keychain` — это специализированное защищенное хранилище, встроенное в систему, которое используется для сохранения чувствительных данных. Оно предоставляет надежную защиту с использованием шифрования и доступа только для авторизованных приложений. Используется для хранения паролей, токенов авторизации, сертификатов и ключей. 1178 | 1179 |
1180 | 1181 | ### 15. 🟡 Какой persistance вы выберете для разных типов данных? 1182 | 1183 | * `UserDefaults`: Подходит для хранения небольших данных, таких как настройки пользователя или флаги. 1184 | * `CoreData`: Используется для сложных данных и отношений между объектами. Идеально для больших объемов данных и случаев, когда нужно кэшировать информацию или работать с локальной базой данных. 1185 | * `SwiftData`: Тоже самое, что и `CoreData`. 1186 | * `Keychain`: Для хранения конфиденциальной информации, такой как пароли и ключи. 1187 | * `Файловая система (FileManager)`: Для работы с файлами (например, изображениями, документами) или для кэширования больших данных, которые не нужно обрабатывать как объекты. 1188 | 1189 | > По своему не самому успешному опыту работы с CoreData скажу так: иногда хранение базы данных в JSON файлах и папках - тоже очень неплохой вариант. 1190 | 1191 |
1192 | 1193 | ## Работа с сетью 1194 | 1195 | ### 1. 🟢 Что такое `REST`? Что такое `RESTful API`? 1196 | 1197 | `REST` - архитектурный подход, который чаще всего используется при построении клиент-севрверных приложений. Сервер и клиент общаются друг с другом посредством HTTP запросов. Клиент отправляет серверу запросы и сообщения с данными, получая данные в ответ, с которыми дальше и может работать. Связь между клиентом и сервером всегда инициирует клиент. 1198 | `RESTful API` - это набор запросов, которые сервер может обработать и предоставить ответ на них от клиентов. Общение с сервером за пределами данного API возможно, но находится за пределами понимания `REST`. 1199 | 1200 |
1201 | 1202 | ### 2. 🟢 Какие виды HHTP запросов вы знаете? Какими пользуетесь чаще всего? 1203 | 1204 | HTTP запросы могут быть следующих типов: 1205 | 1206 | * `GET` - метод, использующийся для получения ресурсов с сервера. 1207 | * `POST` - метод, использующийся для отправки новых ресурсов на сервер. 1208 | * `PUT` - метод, использующийся для отправки новых или уже имеющихся ресурсов на сервер. Если данный ресурс на сервере уже имеется, он будет заменен новым полностью. 1209 | * `PATCH` - метод, использующийся для частичного обновления уже имеющегося ресурса на сервере. В отличии от `POST`, ресурс не перезаписывается полностью, а обновляется только теми данными, которые указаны в запросе. 1210 | * `DELETE` - метод, использующийся для удаления ресурса с сервера. 1211 | 1212 | > Скорее всего, чаще всего вы выпользуетесь `GET` и `POST` 1213 | 1214 |
1215 | 1216 | ### 3. 🟢 Что такое `JSON`? Для чего он используется? 1217 | 1218 | `JSON` - формат данных, который представляет собой файл, содержащий информацию в виде `{ "ключ": значение }`. Данный формат является самым распространенным форматом сообщений между клиентом и сервером при построении клиент-серверных приложений. 1219 | 1220 |
1221 | 1222 | ### 4. 🟢 Как реализовать парсинг `JSON` в iOS? Что такое `Encodable`/`Decodable`? 1223 | 1224 | На сегодняшний день парсинг `JSON` в iOS довольно прост и делается чуть ли не в две строки. Чтобы распарсить `JSON`, необходимо объявить тип, который будет хранить информацию из `JSON`, реализовать протокол `Decodable` данным типом, чтобы он мог парсить контейнер с данными, затем получить данные с сервера, и воспользоваться методом `decode` типа `JSONDecoder`. 1225 | `Encodable` - протокол, реализация которого позволяет любому типу закодировать себя в формат выбранного кодировщика. 1226 | `Decodable` - протокол, реализация которого позволяет любому типу раскодировать себя из формата выбранного декодировщика. 1227 | `Codable` - объеденение `Encodable` и `Decodable`. 1228 | 1229 | ```swift 1230 | struct Model: Codable { 1231 | var name: String 1232 | var lastName: String 1233 | } 1234 | 1235 | // Get data from somehwere 1236 | // JOSN format is 1237 | // { 1238 | // "name": "Mark", 1239 | // "lastName": "White" 1240 | // } 1241 | let data: Data = ... 1242 | 1243 | do { 1244 | let model = try JSONDecoder().decode(Model.self, from: data) 1245 | print(model) // prints Model(name: "Mark", lastName: "White") 1246 | } catch { 1247 | // Handle parsing error here 1248 | } 1249 | ``` 1250 | 1251 |
1252 | 1253 | ### 5. 🟢 Что такое `URLSession`? Для чего его используют? 1254 | 1255 | `URLSession` - встроенный в iOS тип, с помощью которого приложение может совершать запросы к серверу и получать сообщения в ответ. Вы можете создать свою сессию, а можете пользоваться сессией `shared`, которая создается системой для каждого приложения. 1256 | 1257 |
1258 | 1259 | ### 6. 🟢 Что такое `URL` и `URLRequest`? В чем их отличие? Когда нужно использовать какой? 1260 | 1261 | `URL` - встроенный тип, представляющий собой путь к ресурсу, как локальному, так и размещенному удаленно. 1262 | `URLRequest` - встроенный тип, представляющий собой HTTP запрос, который вы можете отправить в сеть. 1263 | 1264 | `URL` и `URLRequest` отличаются тем, что `URLRequest` - это не просто путь к ресурсу, но сам запрос, который содержит путь к ресурсу, а так же информацию, как именно мы будем запрашивать данный ресурс и какое сообщение мы будем отправлять в сеть. `URL` является частью `URLRequest`. 1265 | Как правило вы не используете `URL` напрямик с `URLSession`, вы всегда создаете полноценный `URLRequest`. Однако, использование `URL` с `URLSession` возможно, в таком случае система создат `URLRequest` за вас. Это будет `HTTP GET Request` с путем к ресурсу без дополнительной информации. 1266 | 1267 |
1268 | 1269 | ### 7. 🟡 Какие альтернативы есть URLSession? Назовите их преимущества/недостатки 1270 | 1271 | 1. Alamofire 1272 | - Плюсы: Удобный синтаксис, управление сессиями, поддержка асинхронных операций. 1273 | - Минусы: Внешняя библиотека, может быть избыточной для простых задач. 1274 | 1275 | 2. AFNetworking 1276 | - Плюсы: Проверенная временем, поддержка множества функций. 1277 | - Минусы: Написана на Objective-C, менее популярна. 1278 | 1279 | 3. PromiseKit 1280 | - Плюсы: Упрощает асинхронные операции через Promises. 1281 | - Минусы: Добавляет абстракцию, требует внешней зависимости. 1282 | 1283 | 4. Moya 1284 | - Плюсы: Упрощает работу с API, типизация запросов. 1285 | - Минусы: Сложнее в настройке, лишняя абстракция для простых задач. 1286 | 1287 | 5. Network.framework 1288 | - Плюсы: Низкоуровневый контроль сетевых операций. 1289 | - Минусы: Сложный в использовании, требует ручной настройки. 1290 | 1291 | 6. Socket.IO 1292 | - Плюсы: Реальное время, поддержка WebSocket. 1293 | - Минусы: Только для WebSocket, требует серверной поддержки. 1294 | 1295 | > Если вам нужно получить с сервера пару-тройку JSON файлов и отобразить их на экране, просто используйте URLSession и не создавайте себе лишних проблем. 1296 | 1297 |
1298 | 1299 | ### 8. 🟡 Что такое WebSocket? Для чего он используется? В чем отличие от обычнх HTTP запросов? 1300 | 1301 | WebSocket — это протокол связи, позволяющий устанавливать постоянное двустороннее соединение между клиентом и сервером. Он используется для обмена данными в режиме реального времени. 1302 | 1303 | Отличие от HTTP: 1304 | - WebSocket открывает одно соединение, по которому данные могут передаваться постоянно в обе стороны. 1305 | - HTTP — это одноразовые запросы, где клиент запрашивает данные, а сервер отвечает, закрывая соединение после каждого запроса. 1306 | 1307 | Таким образом, WebSocket экономит ресурсы и время при обмене данными в реальном времени. 1308 | 1309 |
1310 | 1311 | ## Управление памятью 1312 | 1313 | ### 1. 🟢 Что такое счетчик ссылок? Для чего он нужен? 1314 | 1315 | Счетчик ссылок - это механизм всех `reference type` типов в Swift, благодаря которому `reference type` типы работают так, как они работают. Так как при присваивании одному экземпляру `reference type` типа другого экземпляра этого же типа, происходит не копирование реального объекта, а лишь ссылки на него, нам необходимо знать, когда на данный объект никто не будет ссылаться, чтобы мы могли его удалить. Счетчик ссылок как раз и считает ссылки на объект. 1316 | Важно уточнить, что ключевые слова `weak` и `unowned` не влияют на счетчик ссылок. Именно поэтому они всегда являются `Optional` и именно поэтому удается решать проблему `reference cycle`. 1317 | 1318 |
1319 | 1320 | ### 2. 🟢 Что такое reference cycle? Когда он может произойти? Что необходимо сделать, чтобы избежать таких ситуаций? 1321 | 1322 | reference cycle - цикл ссылок или циклическая ссылка, ситуация, при которой один или более объектов указывают друг на друга. Данная ситуация может произойти по разным причинам, однако, самая частая из них - это неявный захват `self` внутри замыкания, которое удерживает `self`. 1323 | Чтобы избежать reference cycle, необходимо одну из ссылок сделать `weak` или `unowned`. Какую именно зависит от реализации программы и бизнес логики. 1324 | 1325 | ```swift 1326 | class ViewController: UIViewController { 1327 | @IBOutlet var titleLabel: UILabel! 1328 | 1329 | let network = Networ() 1330 | 1331 | override func viewDidLoad() { 1332 | super.viewDidLoad() 1333 | 1334 | network.fetch { newTitle in 1335 | self.titleLabel.text = newTitle 1336 | } 1337 | } 1338 | } 1339 | ``` 1340 | 1341 | В примере выше образуется reference cycle. `ViewController` удерживает переменную `network`. При вызове функции `fetch(completionHandler:)` ее `completionHandler` удерживает `self` (`ViewController`). 1342 | Для решения данной проблемы в список захвата `completionHandler` `self` необходимо передать как `weak` 1343 | 1344 | ```swift 1345 | class ViewController: UIViewController { 1346 | @IBOutlet var titleLabel: UILabel! 1347 | 1348 | let network = Networ() 1349 | 1350 | override func viewDidLoad() { 1351 | super.viewDidLoad() 1352 | 1353 | network.fetch { [weak self] newTitle in 1354 | self?.titleLabel.text = newTitle 1355 | } 1356 | } 1357 | } 1358 | ``` 1359 | 1360 | > Обратите внимание, что при реализации делегата, переменная `delegate` так же должна быть `weak`. Это позволяет типу быть собственным делегатом и не указывать сильно самому на себя. Чтобы это было возможно любой протокол делегата должен быть ограничен `AnyObject`. 1361 | 1362 |
1363 | 1364 | ### 3. 🟡 Какая модель работы с памятью в iOS? 1365 | 1366 | iOS использует ARC модель. ARC - Automated Reference Counting - система, которая построена на факте того, что вы не будете работать с объектами напрямик, а будете работать со ссылками на эти объекты. При создании объекта так же создается и первая ссылка на данный объект, которая кладется в переменную/константу, которая инициировала создание объекта. При попытки скопировать такой объект, система будет создавать новую ссылку на уже существующий объект. Таким образом, когда количество ссылок на объект станет равным нулю, объект удаляется. 1367 | Через этот механизм реализованы `reference type` типы Swift и весь ObjC Runtime. 1368 | 1369 |
1370 | 1371 | ### 4. 🟡 Что такое stack и heap? Для чего используюется каждая из них? 1372 | 1373 | `Stack` (стек) — это область памяти, которая используется для хранения локальных переменных и вызовов функций. Он работает по принципу LIFO (последним пришел — первым вышел), что позволяет быстро добавлять и удалять данные. Память в стеке выделяется автоматически, а данные удаляются при завершении функции. Однако у стека ограниченный размер, и он используется для кратковременных операций. 1374 | 1375 | `Heap` (куча) — это область памяти для динамического распределения, которая используется для хранения объектов, живущих дольше времени исполнения функций. Куча более гибкая и позволяет работать с большими объемами данных, но доступ к ней медленнее, чем к стеку. 1376 | 1377 |
1378 | 1379 | ### 5. 🟡 Что такое memory leak? Как вычеслить memory leak? Как его избежать? 1380 | 1381 | `Memory leak` (утечка памяти) — это ситуация, когда программа выделяет память, но не освобождает её, что приводит к тому, что эта память становится недоступной и не используется, но при этом не возвращается системе. Это может со временем привести к исчерпанию памяти и сбоям в работе приложения. 1382 | 1383 | **Как вычислить memory leak:** 1384 | * Профайлеры: Инструменты, такие как Xcode Instruments (Leaks), позволяют отслеживать выделение и освобождение памяти. 1385 | * Инспекторы памяти: Использование встроенных средств разработки для отслеживания объектов, которые продолжают существовать, хотя уже не должны. 1386 | * Логи: Регулярные проверки журналов для выявления ошибок, связанных с некорректным управлением памятью. 1387 | 1388 | **Как избежать memory leak:** 1389 | * Правильное управление ссылками: Использовать слабые ссылки (weak) для предотвращения циклических ссылок, особенно в замыканиях и делегатах. 1390 | * Автоматическое управление памятью: В Swift используется ARC (Automatic Reference Counting), который помогает автоматически управлять памятью, но важно следить за сильными ссылками. 1391 | 1392 |
1393 | 1394 | ### 6. 🔴 Что такое ObjC Runtime? Что такое диспетчиризация методов, dispatch table? Назовите преимущества и недостатки. 1395 | 1396 | `Objective-C Runtime` — это динамическая система, которая отвечает за выполнение программы на языке Objective-C. Она позволяет программам динамически изменять свое поведение во время исполнения, например, добавлять методы или изменять классы. В отличие от статически компилируемых языков, Objective-C активно использует runtime для работы с объектами и вызова методов. 1397 | 1398 | **Диспетчеризация методов:** 1399 | Это процесс выбора и вызова правильного метода во время выполнения программы. В Objective-C каждый вызов метода проходит через систему runtime, которая ищет соответствующую реализацию метода в dispatch table (таблице диспетчеризации). 1400 | 1401 | **Dispatch table (таблица диспетчеризации):** 1402 | Это структура данных, где каждому классу сопоставляется список методов. Когда вызывается метод, программа находит его адрес в таблице и выполняет. 1403 | 1404 | **Преимущества диспетчеризации:** 1405 | - Динамичность: Методы можно добавлять или изменять во время выполнения программы. 1406 | - Гибкость: Можно отправлять сообщения объектам, не зная их конкретного типа (динамическая типизация). 1407 | 1408 | **Недостатки диспетчеризации:** 1409 | - Медленнее, чем статическая компиляция: Поскольку метод ищется в таблице во время выполнения, это медленнее, чем статические вызовы функций. 1410 | - Ошибки во время выполнения: Поскольку проверки типов происходят во время исполнения, ошибки могут не быть выявлены на этапе компиляции. 1411 | 1412 | В целом, Objective-C runtime и диспетчеризация методов обеспечивают мощные возможности для динамического изменения поведения программ, но могут замедлить выполнение программы из-за поиска методов в таблицах. 1413 | 1414 |
1415 | 1416 | ## Асинхронность и многопоточность 1417 | 1418 | ### 1. 🟡 Что такое многопоточность? Что такое concurrency? 1419 | 1420 | `Многопоточность` — это возможность программы выполнять несколько потоков одновременно, чтобы улучшить производительность. 1421 | `Concurrency` — выполнение нескольких задач, которые могут быть независимыми или взаимодействовать друг с другом, переключения между ними. 1422 | 1423 |
1424 | 1425 | ### 2. 🟡 Что такое асинхронное и синхронное исполнение? 1426 | 1427 | **Синхронное** — задачи выполняются последовательно, одна за другой, блокируя выполнение кода. 1428 | 1429 | **Асинхронное** — задачи могут запускаться в фоновом режиме без блокировки основного потока, что позволяет продолжать выполнение программы. 1430 | 1431 |
1432 | 1433 | ### 3. 🟡 Что такое последовательное и параллельное исполнение? Как можно реализовать каждый из типов? 1434 | 1435 | **Последовательное** — задачи выполняются одна за другой, независимо от наличия свободных ресурсов. 1436 | 1437 | **Параллельное** — несколько задач выполняются одновременно, используя несколько потоков или процессоров. 1438 | 1439 | Реализация: последовательное — через основной поток, параллельное — через многопоточность. 1440 | 1441 | > В GCD, к примеру, очереди бывают concurrent и serial, concurrent может выполнять несколько операций одновременно, serial же - только одну. Main Queue - serial, но можно создать и любую другую serial очередь. 1442 | 1443 |
1444 | 1445 | ### 4. 🟡 Какие задачи могут потребовать асинхронного выполнения? 1446 | 1447 | - Сетевые запросы 1448 | - Работа с файлами 1449 | - Тяжелые вычисления, требующие большого времени 1450 | - Загрузка изображений 1451 | 1452 |
1453 | 1454 | ### 5. 🟡 Какие способы выполнения асинхронной работы в iOS вы знаете? 1455 | 1456 | - GCD (Grand Central Dispatch) 1457 | - OperationQueue 1458 | - DispatchGroup 1459 | - Swift Concurrency 1460 | 1461 |
1462 | 1463 | ### 6. 🟡 Что такое GCD? Для чего он используется? 1464 | 1465 | Технология, позволяющая управлять многопоточностью в iOS. Используется для управления потоками. 1466 | 1467 |
1468 | 1469 | ### 7. 🟡 Что такое Operation и OperationQueue? Для чего они используется? 1470 | 1471 | `Operation` — объект, представляющий задачу, которую можно запустить асинхронно. 1472 | 1473 | `OperationQueue` — очередь, в которой задачи (Operation) выполняются асинхронно. 1474 | 1475 |
1476 | 1477 | ### 8. 🟡 Что такое DispatchGroup? Для чего он используется? 1478 | 1479 | Технология используется для объединения нескольких асинхронных задач и получения уведомления, когда все задачи завершены. Кроме того, их можно комбинировать с другими группами, чтобы создать зависимости. При таком построении одна группа будет ждать полного окончания всех операций другой группы и только потом запуститься. 1480 | 1481 |
1482 | 1483 | ### 9. 🟡 Что такое Qos (Quality of Service)? Где использутеся? Для чего? Какие есть уровни? 1484 | 1485 | Определяет приоритет задачи в системе. Уровни от самого приоритетного к менее приорететному: `.userInteractive`, `.userInitiated`, `.default`, `.utility`, `.background`. 1486 | 1487 |
1488 | 1489 | ### 10. 🟡 Что такое race codition? Когда может произойти такая ситуация? Как предотвратить? 1490 | 1491 | Происходит, когда несколько потоков одновременно пытаются прочитать или изменить одну переменную, что может привести к ошибкам. Предотвращается с помощью механизмов синхронизации (mutex, semaphore). 1492 | 1493 | > За пределами mutex и semaphore, которые являются очень низкоуровневыми видами блокировки, есть еще тот же GCD, к примеру, где доступ к данным может быть поставлен на очередь. 1494 | Swift Concurrency решает эту проблему через actor. 1495 | 1496 |
1497 | 1498 | ### 11. 🟡 Что такое deadlock? Когда может произойти такая ситуация? Как предотвратить? 1499 | 1500 | Это ситуация, когда потоки блокируют друг друга, ожидая освобождения ресурса, например синхронный вызов задачи на главном потоке. Предотвращается контролем порядка захвата ресурсов и использованием тайм-аутов. 1501 | 1502 |
1503 | 1504 | ### 12. 🟡 Можно ли реализовать многопоточность на одноядерном процессоре? 1505 | 1506 | Да, возможно. Процессор будет переключаться между потоками (псевдомногозадачность - concurrency). 1507 | 1508 |
1509 | 1510 | ### 13. 🟡 Что такое globalActor и @MainActor? Для чего используются? 1511 | 1512 | `GlobalActor` — деректива языка Swift, которая позволяет сделать любой actor глобальным. Это дает возможность использовать такой actor глобально (как синглтон) и маркировать им другие объявления (струтуры, классы, функции), также обеспечивает выполнение на одном глобальном потоке. 1513 | 1514 | `@MainActor` — частный случай globalActor, гарантирует выполнение кода в основном потоке, который используется для UI-операций. 1515 | 1516 |
1517 | 1518 | ### 14. 🔴 Что такое NSTread? Для чего он используется? 1519 | 1520 | Класс для создания и управления потоками вручную. Сейчас используется реже, так как GCD и OperationQueue проще и эффективнее. 1521 | 1522 |
1523 | 1524 | ### 15. 🔴 Чем отличаются GCD, OperationQueue, DispatchGroup и NSThread? 1525 | 1526 | `GCD` — высокоуровневый фреймворк, абстракция над потоками. 1527 | `OperationQueue` — более высокоуровневый механизм с объектами Operation. 1528 | `DispatchGroup` — для группировки нескольких задач. 1529 | `NSThread` — ручное управление потоками. 1530 | 1531 |
1532 | 1533 | ### 16. 🔴 Что такое mutex? Для чего он используется? 1534 | 1535 | `Mutex` (Mutual Exclusion Object) — это механизм синхронизации, который используется для предотвращения одновременного доступа нескольких потоков к одному ресурсу. Когда один поток захватывает mutex, другие потоки, пытающиеся получить доступ к тому же ресурсу, вынуждены ждать, пока первый поток освободит mutex. Это гарантирует, что только один поток работает с ресурсом в каждый момент времени. 1536 | 1537 |
1538 | 1539 | ### 17. 🔴 Что такое semaphore? Для чего он использутеся? Чем отличается от mutex? 1540 | 1541 | `Semaphore` — это механизм синхронизации, который управляет доступом к ресурсу с возможностью одновременной работы нескольких потоков (в отличие от mutex, который разрешает доступ только одному потоку). Семафор имеет счётчик, который определяет, сколько потоков могут одновременно получить доступ к ресурсу. 1542 | 1543 | Когда поток захватывает семафор, счётчик уменьшается. Если счётчик больше нуля, поток получает доступ к ресурсу. Если счётчик равен нулю, другие потоки будут ждать, пока текущие потоки не освободят семафор. 1544 | 1545 |
1546 | 1547 | ### 18. 🔴 Как обеспечить безопасный доступ к переменной в многопоточной среде? 1548 | 1549 | `Mutex` - захватывать и освобождать mutex при доступе к переменной, чтобы только один поток мог её изменять в данный момент. 1550 | `Semaphore` - можно ограничить количество потоков, которые одновременно изменяют переменную, если доступ не должен быть строго эксклюзивным. 1551 | `Dispatch Barrier` - в GCD можно использовать барьерные блоки, чтобы потоки, записывающие данные, блокировали другие потоки, пока операция не завершится. 1552 | `Atomic операции` - это операции, которые выполняются за одно действие, неделимо, и они гарантируют, что доступ к данным будет безопасным в многопоточной среде. 1553 | `@synchronized` (в Objective-C) - позволяет заблокировать выполнение кода другим потокам, пока текущий поток не завершит работу с защищённой переменной. 1554 | `actor` - это современный механизм для безопасного доступа к данным в многопоточной среде. Он автоматически синхронизирует доступ к своим свойствам и методам, гарантируя отсутствие гонок. Однако, требует Swift 5.5+ и асинхронной модели (с использованием async/await). 1555 | `GCD` - можено использовать Serial Dispatch Queue для последовательного выполнения задач и barrier для параллельных очередей. 1556 | 1557 |
1558 | 1559 | ## Архитектурные подходы 1560 | 1561 | ### 1. 🟢 Что такое клиент-серверная архитектура? В роли кого как правило выступает iOS приложение? 1562 | 1563 | Клиент-серверная архитектура - это подход разработки приложения, при котором есть приложение, которое выступает в роли клиента и сервер, с которым приложение общается, получая оттуда и отправляя туда данные. 1564 | 1565 |
1566 | 1567 | ### 2. 🟢 Что такое `MVC`? Из чего он состоит? Что не так с `Apple MVC`? 1568 | 1569 | `MVC` - Model-View-Controller. Самая базовая архитектура приложения, которую в свое время пытались реализовать Apple, но получилось лишь отчасти. 1570 | `MVC` состоит из: 1571 | 1572 | * `Model` - данные приложения, с которыми мы работаем. 1573 | * `View` - UI приложения и все, что взаимодействует с пользователем. 1574 | * `Controller` - медиатор между `Model` и `View`. Реагирует на изменения `View` и действия пользователя, обновляя `Model`; обновляет `View`, при изменении `Model`. 1575 | 1576 | `Apple MVC` грустно известен как `Massive ViewController`. Изначального разделения между `View` и `Controller` не существует, из-за чего `ViewController` делает слишком много работы и имеет тенденцию становится очень большим и трудно изменяемым. Использования `Apple MVC` необходимо избегать при любой возможности. 1577 | 1578 |
1579 | 1580 | ### 3. 🟢 Что такое `MVP`? Из чего он состоит? 1581 | 1582 | `MVP` - Model-View-Presenter. По сути, это тот же `MVC`, но с менее путающими терминами. Так как в iOS есть `ViewController`, но нет `ViewPresenter`, намного легче представить `ViewController` как `View`, при этом полностью не запутавшись в том, кто и чем должен заниматься. 1583 | `MVP` состоит из: 1584 | 1585 | * `Model` - данные приложения, с которыми мы работаем. 1586 | * `View` - UI приложения и все, что взаимодействует с пользователем. 1587 | * `Presenter` - медиатор между `Model` и `View`. Реагирует на изменения `View` и действия пользователя, обновляя `Model`; обновлет `View`, при изменении `Model`. 1588 | 1589 |
1590 | 1591 | ### 4. 🟡 Что такое `MVVM`? Из чего он состоит? 1592 | 1593 | `MVVM` - Model-View-ViewModel. Еще одна вариация `MVC`, но уже с реактивным подходом (как правило). Данная архитектура характерна тем, что обновления получаются посредством канала связи, а не запросом на состояние. 1594 | `MVVM` состоит из: 1595 | 1596 | * `Model` - данные приложения, с которыми мы работаем. 1597 | * `View` - UI приложения и все, что взаимодействует с пользователем. 1598 | * `ViewModel` - медиатор между `Model` и `View`. `ViewModel` подписывается на обновления `Model`, обновляя `View`, а так же подписывается на события `View`, обновляя `Model`. 1599 | 1600 | > `MVVM` можно реализовать и без реактивного программирования, но тогда это будет больше похоже на `MVP` 1601 | 1602 |
1603 | 1604 | ### 5. 🟡 Что такое `VIPER`? Из чего он состоит? 1605 | 1606 | `VIPER` - View-Interactor-Presenter-Entity-Router. `VIPER` - это попытка создать кольцо всевластия. Единая архитектура, которая хороша во всем и решает все проблемы человечества. К сожалению, мы живем в неидеальном мире и ничего подобного быть не может, так что и у `VIPER` есть свои недостатки. 1607 | VIPER состоит из: 1608 | 1609 | * `View` - UI приложения и все, что взаимодействует с пользователем. 1610 | * `Interactor` - Обработчик всех событий и изменений, реализующий всю бизнес логику приложения. 1611 | * `Presenter` - компонент, отвечающий за то, как именно должен обновиться View (состояние, анимации, переходы в пределах одного `VIPER` модуля). 1612 | * `Entity` - данные приложения, с которыми мы работаем. 1613 | * `Router` - компонент, отвечающий за переход между разными `VIPER` модулями. 1614 | 1615 | Как правило один `VIPER` модуль - это один экран приложения, но данное правило не является строгим. 1616 | 1617 | > Про `VIPER` довольно часто любят спрашивать, но слава богу, его практически не используют, по крайней мере в чистом виде. 1618 | > Я бы избегал этого подхода как чумы. Он прекрасен лишь на бумаге, на практике его поддержка превращается в ад, его невозможно выдержать в чистом виде и весь код превращается в кашу, техдолг и тонну нарушений собственных правил. 1619 | 1620 |
1621 | 1622 | ### 6. 🔴 Что не так с VIPER? Какие минусы разных архитектурных подходов вы находили и как их решали? 1623 | 1624 | Проблемы с VIPER начинаются ровно тогда, когда вы пытаетесь реализовать на нем любой проект, пытаясь соблюдать VIPER от и до. Каждый экран, фича, компонент потребуют своего VIPER модуля, что вынуждает вас писать очень много поддерживающего кода для даже самой маленькой реальной функциональности, просто, чтобы соответствовать архитектуре. 1625 | В принципе, это касается любого подхода, просто с VIPER это максимально наглядно. Именно по-этому лучше относится к архитектурам не как к правилам и законам, а как к рекомендациям, применение которых всегда должно быть оправдано. 1626 | 1627 |
1628 | 1629 | ### 7. 🔴 В чем разница между MVC, MVP, MVVM и VIPER? Какие еще архитектурные подходы вы знаете? 1630 | 1631 | Из описания ответов на вопросы про MVC, MVP и MVVM можно сделать вывод, что это практически одно и тоже, с разницей на имена и стиль программирования. VIPER же отличается от них тем, что пытается решить те вопросы, которые MVC/MVP/MVVM просто не покрывает. 1632 | 1633 | Здесь вы можете привести примеры других архитектурных подходов, с которыми вам доводилось работать, или недостатки которых вы знаете. 1634 | 1635 |
1636 | 1637 | ### 8. 🔴 Какие критерии выбора архитектуры при разработки приложения/фичи? 1638 | 1639 | Здесь правильного ответа нет. Просто называете то, как бы вы реально выбирали подходы и чем бы руководствовались. 1640 | 1641 | > Совет: не пытайтесь здесь блистать знаниями. Человек, который будет делать что-то очень сложное, навороченно, гибкое и динамическое при любом раскладе, вызывает куда больше вопросов, чем человек, который отталкивается от реальных условий и требований и выбирает тот подход, который лучше всего ляжет на то, что у него есть. 1642 | 1643 |
1644 | 1645 | ### 9. 🔴 Слышали ли вы про TCA? 1646 | 1647 | Если да, то опишите свой опыт с этим фреймворком и свои впечатления от него. Если вы заметили какие-то недостатки или места, требующие доработки, обязательно расскажите об этом. Если бы вы выбрали что-то другое вместо TCA, скажите что и почему. 1648 | 1649 |
1650 | 1651 | ## Debug 1652 | 1653 | ### 1. 🟢 Какие инструменты отладки в Xcode вы знаете? Какими пользовались? 1654 | 1655 | Вы можете перечислить любые, которые знаете, но дебаггер и логгирование должны быть обязательно. 1656 | 1657 |
1658 | 1659 | ### 2. 🟢 Для чего используется логгирование? Какие уровни логгирования бывают? 1660 | 1661 | Логгирование - механизм фиксации и отображения текущего состояния выполнения приложения. 1662 | Чаще всего встречаюся следующие уровни логгирования: 1663 | 1664 | * `debug` - с таким уровнем записываются сообщения, имеющие смысл только при отладке программы. 1665 | * `info` - с таким уровнем записываются сообщения, несущие вспомогательную информацию. 1666 | * `default`/`verbose` - с таким уровнем записываются сообщения, несущие основную или важную информацию. 1667 | * `error`/`warning` - с таким уровнем записываются сообщения, несущие информацию об ошибке или предупреждении, не завершающие работу программы. 1668 | * `fault`/`error` - с таким уровнем записываются сообщения, несущие информацию об ошибке, в результате которой дальнейшее выполнение программы невозможно. 1669 | 1670 |
1671 | 1672 | ### 3. 🟢 Что такое llvm? 1673 | 1674 | llvm - это интерфейс дебаггера, который мы можем использовать через командную строку во время отладки внутри Xcode. llvm имеет множество команд, которые помогают отследить и найти ошибку в программе или отобразить информацию о текущем состоянии программы. 1675 | 1676 | > llvm знать весь, конечно же, не обязательно, но хотя бы основыне команды знать желательно, ибо все мы знаем как хорошо работает Xcode. 1677 | 1678 |
1679 | 1680 | ### 4. 🟢 Что такое View Hierarchy Debugger? 1681 | 1682 | View Hierarchy Debugger - это инструмент, встроенный в Xcode, который позволяет захватить текущий UI с экрана и разложить его на слои, предоставляя возможность визуально оценить верность отображения UI относительно дизайна, а так же отследить ошибки или не соответствия. 1683 | 1684 | > К сожалению практически бесполезен при дебаге SwiftUI. 1685 | 1686 |
1687 | 1688 | ### 5. 🟡 Что такое thread sanitiser? 1689 | 1690 | `Thread Sanitizer` (TSan) — это инструмент для выявления ошибок в многопоточном коде, таких как race conditions (ситуации, когда несколько потоков одновременно изменяют данные, что может привести к непредсказуемым результатам) и проблемы с синхронизацией. Он помогает разработчикам находить потенциальные проблемы, которые могут возникать только при специфических условиях и часто трудно обнаружимы в тестах. 1691 | 1692 | **Как работает Thread Sanitizer:** 1693 | - Анализирует доступ к памяти: TSan отслеживает все операции с памятью (чтение, запись) в разных потоках и проверяет, не происходят ли они одновременно без должной синхронизации. 1694 | - Выявляет некорректное использование потоков: например, отсутствие блокировок или использование неправильных механизмов синхронизации. 1695 | - TSan выявляет работу с UI с неглавного потока, что является одной из его самых важных функций. 1696 | 1697 | **Преимущества:** 1698 | - Раннее выявление ошибок: находит ошибки на этапе тестирования, до того как они проявятся у пользователей. 1699 | - Интеграция с Xcode: TSan встроен в Xcode и легко включается для анализа многопоточных приложений. 1700 | 1701 | **Недостатки:** 1702 | - Снижение производительности: запуск программы с включённым TSan замедляет её работу, поскольку инструмент проверяет каждую операцию с памятью. 1703 | - Ложные срабатывания: иногда может выявлять потенциальные проблемы, которые на практике не вызывают ошибок. 1704 | 1705 |
1706 | 1707 | ### 6. 🟡 Что такое memory graph? 1708 | 1709 | `Memory Graph` — это инструмент в Xcode, который позволяет разработчикам визуализировать и анализировать структуру объектов в памяти приложения во время его выполнения. Он помогает найти утечки памяти (memory leaks) и циклы сильных ссылок (retain cycles), которые могут приводить к увеличению потребления памяти и ухудшению производительности. 1710 | 1711 | **Что показывает Memory Graph:** 1712 | - Дерево объектов: показывает, какие объекты существуют в памяти, их связи друг с другом, и какие объекты удерживаются (через ссылки). 1713 | - Утечки памяти: отмечает объекты, которые не были освобождены, даже если они больше не используются. 1714 | - Циклы сильных ссылок: отображает объекты, которые удерживают друг друга через сильные ссылки, что не позволяет им быть освобожденными. 1715 | 1716 |
1717 | 1718 | ### 7. 🟡 Какие инструменты вы используете для дебага UI приложения? 1719 | 1720 | Вы можете использовать все, что угодно, но про View Hierarchy Debugger вы точно должны упомянуть. Все остальное - плюс в копилочку скиллов и карму. 1721 | 1722 |
1723 | 1724 | ## Git 1725 | 1726 | ### 1. 🟢 Что такое система контроля версий? Какие вам известны и какие вы использовали? 1727 | 1728 | Система контроля версий - это программа или утилита, которая позволяет хранить ваш код а так же записывать все ваши изменения в нем. Помогает не только в распространении кода между разработчиками, но и для отслеживания изменений во времени, слиянии разного кода в одном и том же участке. 1729 | Вам должно быть известно как минимум про git, остальные СКВ по желанию. 1730 | 1731 |
1732 | 1733 | ### 2. 🟢 Что такое `push`/`pull`/`fetch`/`merge`? 1734 | 1735 | Рассмотрим данные команды на примере git: 1736 | * `push` - команда, которая отправляет ваши текущие закоммиченные изменения в репозиторие на удаленный репозиторий (remote) 1737 | * `pull` - команда, которая проверяет наличие новых коммитов на удаленном репозитории и скачивает их, если они присутствуют 1738 | * `fetch` - команда, которая проверяет наличие новых коммитов на удаленном репозитории, но не скачивает их 1739 | * `merge` - команда, которая сливает две вертки репозитория в одну. При выполнении данной команды могут возникнуть конфликты. 1740 | 1741 |
1742 | 1743 | ### 3. 🟢 Что такое `Git Flow`? Опишите основные принципы данного подхода 1744 | 1745 | `Git Flow` - это порядок взаимодействия разработчиков с репозиторием, призванный минимизировать риски при выкатывании новых версий программы. 1746 | Как правило Git Flow описывает систему релиза вашей программы через релиз ветки, по следующей схеме: 1747 | * При подготовке нового релиза программы создается релиз ветка. 1748 | * Для каждой новой фичи данного релиза создается ветка фичи от ветки релиза. 1749 | * При выполнении фичи, ветка фичи мержится в ветку релиза, тем самым выполняя требования данного релиза. 1750 | * При достижении всех требований релиза, тестирования и прочих проверок, ветка релиза мержится в master/main ветку репозитория. 1751 | 1752 |
1753 | 1754 | ### 4. 🟢 Что такое Pull/Merge Request? Зачем их используют? Что такое Code Review? 1755 | 1756 | `Pull/Meger Request` - это механизм web интерфейса удаленного репозитория, при котором мы не мержем изменения из одной ветки в другую, а создаем запрос на такой мерж. Web интерфейс позволяет другим участникам репозитория увидеть изменения, который собираются быть смержены перед тем, как они будут смержены. 1757 | Процесс оценивания данных изменений называется Code Review. В ходе Code Review могут быть предложены правки, предложения, выставлены замечания к автору запроса. 1758 | 1759 |
1760 | 1761 | ### 5. 🟡 Для чего нужен .gitignore файл? 1762 | 1763 | .gitignore файл - это специальный файл, который использует git, в котором описываются все файлы и папки, которые не должны попадать в репозиторий. Шаблон такого файла для любого языка/платформы с легкостью находятся в интернете, а Xcode, при создании репозитория через него, с недавних пор и сам научился создавать этот файл за вас со всем, что там должно быть для любого iOS приложения. 1764 | Однако, это не значит, что вы не можете/вам не понадобится добавлять туда что-то свое. 1765 | 1766 |
1767 | 1768 | ### 6. 🟡 Чем отличается `merge` от `rebase`? Как решаются конфликты при использовании git? 1769 | 1770 | `Merge` - это команда слияния двух веток в одну, в результате чего создается новый коммит. При этом вся история коммитов сохраняется. 1771 | `Rebase` - это команда, которая просто форсированно меняет родительскую ветку вашей ветки на указанную, сливая изменения воедино. В результате данной операции коммит не создается. 1772 | 1773 | При выполнении этих команд у вас могут возникнуть конфликты, ситуации, при которых, один и тот же участок кода был модифицирован в обоих ветках и какой из вариантов выбрать система решить автоматически не может. Чтобы решить эти конфликты лучше всего использовать любую программу или утилиту, которая позволит вам увидеть разницу между двумя ветками и решить какой код использовать. На сегодняшний день практически любая программа, которая имеет встроенный git, умеет это делать. Даже Xcode. 1774 | 1775 |
1776 | 1777 | ### 7. 🟡 Что такое Git hook? Для чего они используются? Использовали ли вы на практике? 1778 | 1779 | `Git hook` — это скрипты, которые автоматически выполняются при определённых действиях в системе контроля версий Git. Они позволяют автоматизировать различные процессы, связанные с управлением репозиторием, например, проверку кода перед коммитом, обновление зависимостей или автоматическое развертывание. 1780 | 1781 |
1782 | 1783 | ### 8. 🔴 Как перенести репозиторий с одного сервиса на другой? Как при этом сохранить историю коммитов? 1784 | 1785 | Чтобы перенести репозиторий с одного сервиса (например, с GitHub на GitLab) на другой и сохранить всю историю коммитов, можно выполнить следующие шаги: 1786 | 1787 | **1. Клонирование текущего репозитория:** 1788 | 1789 | ```bash 1790 | git clone --mirror 1791 | ``` 1792 | 1793 | Опция --mirror создаёт точную копию репозитория, включая все ветки, теги и коммиты. 1794 | 1795 | **2. Создание нового репозитория на новом сервисе:** 1796 | Перейдите на новый сервис (например, GitLab) и создайте пустой репозиторий. 1797 | 1798 | **3. Добавление нового удалённого репозитория:** 1799 | 1800 | ```bash 1801 | cd <название-репозитория> 1802 | git remote set-url origin 1803 | ``` 1804 | 1805 | **4. Отправка данных в новый репозиторий:** 1806 | 1807 | ```bash 1808 | git push --mirror 1809 | ``` 1810 | 1811 | Это перенесёт все ветки, теги и историю коммитов в новый репозиторий. 1812 | 1813 | **5. Проверка:** 1814 | Убедитесь, что все данные перенесены корректно, и история коммитов сохранена. Откройте новый репозиторий на сервисе и посмотрите, что ветки, теги и коммиты находятся на своих местах. 1815 | 1816 | **6. (Опционально) Удаление старого удалённого репозитория:** 1817 | 1818 | ```bash 1819 | git remote remove <старый-репозиторий> 1820 | ``` 1821 | 1822 |
1823 | 1824 | ## Тестирование 1825 | 1826 | ### 1. 🟢 Что такое unit тесты? Для чего они нужны? 1827 | 1828 | Unit тесты - отдельные функции или целые подпрограммы, проверяющие корректность работы вашего кода. Unit они называются от того, что каждый тест/набор тестов должен проверять отдельно взятый фрагмент/модуль/unit программы. 1829 | 1830 | > Это очень сложная тема с точки зрения комьюнити. Лично я тесты не очень люблю и практически никогда не пишу их, в то время, как есть люди, которые буквально не будут с вами общаться, если вы не исповедуете тестирование. 1831 | 1832 |
1833 | 1834 | ### 2. 🟡 Какие преимущества и недостатки предоставляют unit тесты? 1835 | 1836 | **Преимущества** unit-тестов заключаются в том, что они позволяют быстро находить и устранять ошибки на ранних стадиях разработки. Они помогают разработчикам локализовать проблемы в коде, так как проверяют отдельные функции и методы в изоляции. Это делает код более устойчивым к изменениям, поскольку наличие тестов снижает риск нарушить существующую функциональность при рефакторинге. Кроме того, unit-тесты автоматизируются, что ускоряет процесс проверки кода при каждом изменении, и часто служат дополнительной документацией, показывая, как должны работать функции. 1837 | 1838 | Однако, **недостатки** unit-тестов включают в себя дополнительные затраты времени на их написание и поддержку. Тесты охватывают только ограниченный набор сценариев, и их успешное прохождение не гарантирует, что приложение в целом работает правильно, особенно на уровне интеграции между модулями. Кроме того, unit-тесты не покрывают пользовательские интерфейсы и требуют дополнения другими видами тестирования для более полной проверки приложения. 1839 | 1840 |
1841 | 1842 | ### 3. 🟡 Назовите три основных блока unit теста 1843 | 1844 | `Arrange` (Подготовка): В этом блоке происходит настройка всех необходимых данных, объектов и зависимостей для тестируемого кода. Здесь вы создаёте условия, в которых будет проверяться функция или метод. 1845 | `Act` (Действие): Выполнение тестируемого метода или функции с подготовленными данными. Это основное действие, которое запускает поведение, требующее проверки. 1846 | `Assert` (Проверка): В этом блоке осуществляется проверка того, что результат работы тестируемого кода соответствует ожидаемому. Это финальный шаг, который определяет, прошёл тест или нет. 1847 | 1848 |
1849 | 1850 | ### 4. 🟡 Чем отличается Stub от Mock? 1851 | 1852 | Stub - обычных тестовый объект. При использовании его все тесты должны проходить. 1853 | Mock - умный Stub. Тесты должны проходить не только используя данный объект, но и задействуя его. 1854 | 1855 |
1856 | 1857 | ### 5. 🟡 Что такое TDD? Какие у него преимущества/недостатки перед другими подходами? 1858 | 1859 |
1860 | 1861 | ### 6. 🔴 Что такое интеграционные тесты? Для чего они используются? 1862 | 1863 |
1864 | 1865 | ### 7. 🔴 Что такое UI тесты? Для чего они нужны? 1866 | 1867 |
1868 | 1869 | ### 8. 🔴 Что такое Snapshot тесты? Для чего они нужны? 1870 | 1871 |
1872 | 1873 | ### 9. 🔴 Если в приложении нет ни одного теста, как вы будете расставлять приоритеты для написания unit тестов? Будете ли вы писать тесты в принципе? 1874 | 1875 |
1876 | 1877 | ## Зависимости и сторонние библиотеки 1878 | 1879 | ### 1. 🟢 Что такое dependency manager? Для чего они используются? Какие приходилось использовать? 1880 | 1881 | Dependency manager - это программа или утилита, которая упралвляет зависимостями, которые использует ваш проект. 1882 | На сегодняшний день существуют три самых популярных менеджера зависимостей: 1883 | 1884 | * CocoaPods 1885 | * Carthage 1886 | * Swift Package Manager (SPM) 1887 | 1888 | > С появлением SPM необходимость использовать что-либо еще отпала полностью, но все еще случаются проекты, где на SPM не перешли или перешли не полностью в силу разных обстоятельств. 1889 | > Кстати, если вы затягиваете зависимости руками или копируете чужой код себе в репозиторий, об этом тоже можно упомянуть. 1890 | 1891 |
1892 | 1893 | ### 2. 🟢 Что такое CocoaPods? Как их использовать? 1894 | 1895 | CocoaPods - это dependency manager, утилита, которая помогает работать с внешними зависимостями и добавлять их в ваш проект. 1896 | Чтобы использовать CocoaPods, необходимо сначала скачать их любым удобным для вас способом и затем использовать их интерфейс через терминал. 1897 | Сами зависимости и настройки проекта описываются в файле Podfile. 1898 | 1899 | > Если вы используете мак с Apple Silicon, то любой удобный для вас способ только один - homebrew. Установив CocoaPods другим способом у вас могут быть проблемы с их запуском без rosetta. 1900 | 1901 |
1902 | 1903 | ### 3. 🟢 Что такое Carthage? Как его использовать? 1904 | 1905 | Carthage - это dependency manager, утилита, которая помогает работать с внешними зависимостями и добавлять их в ваш проект. 1906 | Чтобы использовать Carthage, необходимо сначала скачать их любым удобным для вас способом и затем использовать их интерфейс через терминал. 1907 | Сами зависимости и настройки проекта описываются в файле Cartfile. 1908 | 1909 |
1910 | 1911 | ### 4. 🟢 Что такое Swift Package Manager (SPM)? Как его использовать? 1912 | 1913 | Swift Package Manager - это dependency manager, утилита, которая помогает работать с внешними зависимостями и добавлять их в ваш проект. 1914 | На сегодняшний день, чтобы использовать Swift Package Manager, вам не нужно ничего устанавливать или настраивать дополнительно. Все зависимости SPM описываются прямо в файле проекта, настраиваются через интерфейс Xcode, там же скачиваются и добавляются в зависимости проекта. 1915 | Альтернативно вы можете не подключать все пакеты к файлу проекта, а создать один пакет, который будет подключен к проекту и будет иметь зависимости на все остальные пакеты. Это позволяет минимизировать изменения файла проекта, который, как мы знаем, любит становится монструозно огромным в течении жизни. 1916 | 1917 |
1918 | 1919 | ### 5. 🟡 В чем отличие CocoaPods, Carthage и SPM? Какие у них преимущества/недостатки? 1920 | 1921 | CocoaPods и Carthage имеют в себе мало различий и уже являются всего-лишь историей iOS разработки. В силу ограниченности сторонних программ обе этих системы создавать множество дополнительных и вспомогательных файлов для своей работы, назначение и формат которых был понятен далеко не каждому. Решать проблемы в этих конфигурациях как правило было очень болезненно и долго. 1922 | SPM отличается от всех остальных просто потому, что он встроен в Xcode и написан Apple. Имея прямой доступ к IDE, настройкам проекта и линковщику, SPM минует множество шагов и напрямую работает с build системой. Описания пакетов пишутся тоже на Swift, что позволяет не учить новый язык программирования, чтобы понять как и что надо настраивать. 1923 | 1924 |
1925 | 1926 | ## CI/CD и дистрибуция 1927 | 1928 | ### 1. 🟡 Что такое CI (continuous integration)? 1929 | 1930 |
1931 | 1932 | ### 2. 🟡 Что такое CD (continuous delivery)? 1933 | 1934 |
1935 | 1936 | ### 3. 🟡 Что такое AppStore Connect? Для чего его используют? 1937 | 1938 |
1939 | 1940 | ### 4. 🟡 Что такое Testflight? Для чего его используют? 1941 | 1942 |
1943 | 1944 | ### 5. 🟡 Как распространить билд в AppStore Connect и Testflight? 1945 | 1946 |
1947 | 1948 | ### 6. 🟡 Что такое bundle identifier? 1949 | 1950 |
1951 | 1952 | ### 7. 🟡 Что такое provisioning profile? 1953 | 1954 |
1955 | 1956 | ### 8. 🟡 Что такое development certificate? 1957 | 1958 |
1959 | 1960 | ### 9. 🟡 Что такое entitlements файл? Что в нем находится? 1961 | 1962 |
1963 | --------------------------------------------------------------------------------