Тех собес на senior IOS Разработчик в ****

Доступно с премиум-подпиской

Оформите премиум-подписку, чтобы получить доступ к:

  • Фильтрации по компаниям
  • Названиям компаний в интервью
  • Видеозаписям собеседований в категории IOS Разработчик

Посмотреть видео в категории

(2025-01-30)

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. Какие есть замечания или улучшения?

Вложения

37_1076_photo.jpg

37_1077_photo.jpg

37_1079_photo.jpg