Swift Language Features / Optionals
enum CustomOptional<T>: ExpressibleByNilLiteral {
init() {
self = .none
}
case none
case some(T)
}
let i: CustomOptional<Int> = nil
let i: CustomOptional<Int> = .none
- Объясните реализацию
CustomOptionalи ее использование.
Protocols
protocol Returnable {
associatedType Kind
}
func returnTheType<T: Returnable>(object: T) -> T.Kind {
fatalError()
}
- Объясните использование
associatedTypeв протоколеReturnable.
Swift Collections
var array = [0, 1, 2]
for i in 3...10_000_000_000 { // Условно много раз добавляем в конце элементы
array.append(i)
}
- Обсудите производительность и особенности работы с коллекциями при большом количестве операций добавления.
let dict = ["one": 1, "two": 2, "three": 3]
let dictArbitraryPair = dict["one"]
var dict: [String: Int?] = [
"one": 1,
"two": 2,
"none": nil
]
print(dict.count) // что тут выведется?
dict["two"] = nil
dict["none"] = .some(nil)
// updateValueForKey
print(dict.count) // а здесь?
let a = dict["one"] // Какой тип?
-
Что будет выведено
print(dict.count)в первом случае? -
Что будет выведено
print(dict.count)во втором случае? -
Какой тип будет у переменной
aпослеlet a = dict["one"]? -
Создайте функцию, которая вернет массив уникальных чисел отсортированных по убыванию.
- Пример:
let array = [[7,72,3,4], [1,3,4,4,4,65], [6,3,4,5,6,1,1,1,6,9]] -> [72, 65, 9, 7, 6, 5, 4, 3, 1] - Предложенное решение:
func getArr(_ array: [[Int]]) -> [Int] { let result = Set(array.flatMap { $0 }).sorted(by: >) return Array(result) }
- Пример:
-
Напишите
compactMapдля массива опциональных интов без использования функций высшего порядка.-
Предложенное решение:
extension Array where Element == Int? { func compactMap<T>(_ closure: (Element) -> T?) -> [T] { var result: [T] = [] for element in self { if let closuredElement = closure(element) { result.append(closuredElement) } } return result } }
-
Reference vs. Value Types
var elements = [1,2,3]
for e in elements {
print(e)
elements = [4,5,6]
}
- Объясните поведение цикла
for e in elements { print(e); elements = [4,5,6] }.
class A {
var a: A?
}
struct B {
var b: [B]?
}
struct C: Codable {
var c: CustomList<C>?
}
-
Обсудите особенности работы с ссылочными и значимыми типами на примерах
class A,struct B,struct C. -
Задача по ссылочным и значимым типам (из изображения)
class MyView: CustomStringConvertible { let index: UInt var ID: String init(withIndex index: UInt) { self.index = index ID = String(index) } var description: String { return "((index), (ID))" } } class MyViewController { var strings: [String]() var views: [MyView]() } class FirstViewController: MyViewController { } class SecondViewController: MyViewController { } var firstVC = FirstViewController() var secondVC = SecondViewController() firstVC.strings = ["One", "Two", "Three"] firstVC.views = [MyView(withIndex: 1), MyView(withIndex: 2), MyView(withIndex: 3)] secondVC.strings = firstVC.strings secondVC.views = firstVC.views secondVC.strings.popLast() print(firstVC.strings) secondVC.views.last?.ID = "4" print(firstVC.views)- Определите, что будет выведено в консоль для
print(firstVC.strings)иprint(firstVC.views)после выполнения данного кода. Объясните поведение ссылочных и значимых типов.
- Определите, что будет выведено в консоль для
ARC (Automatic Reference Counting)
class TestClass {
var name = ""
var block1: (()->Void)?
var block2: (()->Void)?
func test() {
self.block1 = { [unowned self] in
self.block2 = {
print(self)
}
self.block2?()
}
self.block1?()
}
deinit {
print("deinit")
}
}
var testObject: TestClass? = TestClass()
testObject?.test()
testObject = nil
- Проанализируйте данный код с
TestClassиblock1,block2. Объясните, когда будет вызванdeinitи почему.
Concurrency (GCD, Threads, Async/Await)
let main = DispatchQueue.main
let serial = DispatchQueue(label: "serial")
let concurrent = DispatchQueue(label: "concurrent", attributes: .concurrent)
main.async {
print(1)
}
main.async {
print(2)
serial.async {
print(3)
}
serial.sync {
print(4)
concurrent.sync {
print(5)
concurrent.sync {
print(6)
}
serial.sync {
print(7)
}
}
}
}
serial.sync {
print(8)
}
- Определите порядок вывода чисел для данного кода с
DispatchQueue.
var count = 0
let group = DispatchGroup()
let locker = NSLock()
group.enter()
let thread1 = Thread {
for _ in 0...999 {
locker.lock()
count += 1
locker.unlock()
}
group.leave()
}
group.enter()
let thread2 = Thread {
for _ in 0...999 {
locker.lock()
count += 1
locker.unlock()
}
group.leave()
}
thread1.start()
thread2.start()
group.notify(queue: .global()) {
print(count)
}
- Какое значение будет выведено для
countв данном коде сNSLockиDispatchGroup? Объясните механизм синхронизации.
func viewDidLoad() {
for i in 0..<10 {
Task {
print(i)
}
}
}
- Объясните поведение и возможные проблемы в данном коде с
TaskвнутриviewDidLoad.
Design Patterns / Architecture
-
Задача по логированию аналитики (из изображения)
// has to log analytics events in console final class Screen1ViewController: UIViewController { init(analytics: AnalyticsClient) { self.analytics = analytics } override func viewDidAppear(animated: Bool) { super.viewDidAppear(animated: animated) analytics.report(AnalyticsEvent(name: "screen1_did_appear", params: [:])) } override func viewDidDisappear(animated: Bool) { super.viewDidDisappear(animated: animated) analytics.report(AnalyticsEvent(name: "screen1_did_disappear", params: [:])) } } // has to log analytics events in file final class Screen2ViewController: UIViewController { init(analytics: AnalyticsClient) { self.analytics = analytics } override func viewDidAppear(animated: Bool) { super.viewDidAppear(animated: animated) analytics.report(AnalyticsEvent(name: "screen2_did_appear", params: [:])) } override func viewDidDisappear(animated: Bool) { super.viewDidDisappear(animated: animated) analytics.report(AnalyticsEvent(name: "screen2_did_disappear", params: [:])) } }- Предложите рефакторинг кода для логирования аналитики в консоль и файл, учитывая дублирование.
-
Задача по паттерну Command (из изображения)
class AddCommand: Command { private var array: [String] private var element: String init(element: String, array: [String]) { self.element = element self.array = array } func execute() { array.append(element) } func undo() { array.removeLast() } } class CommandManager { private var undoArray = [Command]() private var redoArray = [Command]() func execute(command: Command) { command.execute() undoArray.append(command) redoArray.removeAll() } func undo() { guard let command = undoArray.removeLast() else { return } command.undo() redoArray.append(command) } func redo() { guard let command = redoArray.removeLast() else { return } command.undo() // В оригинальном коде здесь 'command.undo()', что, вероятно, является ошибкой и должно быть 'command.execute()' или 'command.redo()' undoArray.append(command) } }- Проанализируйте данный код, реализующий паттерн Command с функциональностью undo/redo. Какие есть замечания или улучшения?
Вложения


