Тех собес на middle-senior IOS Developer в ****

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

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

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

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

(2024-07-23)

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

protocol Weapon { associatedtype Kind: Equatable // Swift protocols w a/t usage constraints, generic where clause func getKind() -> Kind } func compareContainerValue<C1: Weapon, C2: Weapon>(container1: C1, container2: C2) -> Bool { container1.getKind() == container.getKind()

Вопрос: Найти и исправить ошибки в функции compareContainerValue, позволив реализовать сравнение. Такой ответ не устроил, хотят что-то другое:

func compareContainerValue<C1: Weapon, C2: Weapon>(container1: C1, container2: C2) -> Bool where C1.Kind == C2.Kind { return container1.getKind() == container2.getKind() }

Задача 2.

enum Optional<T> {
    case none
    case value(T)
}

func ??<T> // nil-coalescing operator imp
////

Вопрос: Нужно написать самому пользовательский оператор нилового коалесцирования (кароч написать реализацию «??»): Ответ: Написать нужно что-то такое:

enum Optional<T> { case none case value(T) } infix operator ?? func ??<T>(optional: Optional<T>, defaultValue: @autoclosure () -> T) -> T { switch optional { case .none: return defaultValue() case .value(let value): return value } } // Usage examples: let someValue: Optional<Int> = .value(5) let noValue: Optional<Int> = .none let result1 = someValue ?? 10 // result1 will be 5 let result2 = noValue ?? 10 // result2 will be 10

Задача 3

////
/*
 - номинально RAM и swap-файла хватит для того, чтобы заполнить массив (по всему циклу пройтись)
 - однако в RAM есть что-то еще
*/

var integerArray = [Int?]()
(0...999_999_999_999_999_999).forEach {
    integerArray.append($0)
}

Вопрос: Что будет если запустить такой цикл. Ответ: Тут дохрена раз увеличивается массив, становится все больше. Хочет услышать о ресайзинге (увеличение размера массива) переполняемости и последующей перезаписи массива. Что будет когда пздц дохрена большой массив будет. Когда массив увеличивается, создается новый массив с большим размером, и все элементы из исходного массива копируются в новый массив. Обычно размер увеличивается в два раза, чтобы минимизировать количество таких операций и сделать их менее частыми. Это делает добавление элементов через .append() достаточно эффективным, хотя и не таким быстрым, как добавление элементов в массив с заранее известным и фиксированным размером.  Увеличение размера массива: Каждый раз, когда массив достигает своей текущей емкости, создается новый, более крупный массив, и все элементы копируются в него. Этот процесс продолжается до тех пор, пока есть свободная память.  Пределы памяти: Когда массив достигает пределов доступной памяти, приложение может столкнуться с ошибками, такими как out of memory (недостаток памяти), что приведет к аварийному завершению работы приложения. Пути решения: 1. Предварительное резервирование памяти: Используйте reserveCapacity(_:), если знаете приблизительное количество элементов. С помощью него можно зарезервировать кол-во нужных элементов

var array = [Int]() array.reserveCapacity(1000) for i in 1...1000 { array.append(i) }

2. Освобождение памяти: Очищайте массивы, которые больше не нужны, с помощью метода removeAll(). Ниже приведен пример, который демонстрирует, как можно очищать массив в цикле через каждые N итераций:

2. var integerArray = [Int?]()
let threshold = 100_000_000 // Количество элементов, после которого массив очищается

(0...999_999).forEach {
    integerArray.append($0)

    if $0 % threshold == 0 && $0 != 0 {
        print("Array count before removing: (integerArray.count)")
        integerArray.removeAll()
        print("Array cleared. Iteration: ($0)")
    }
}

Задача 4. // реализовать функционал оригинального compactMap ТОЛЬКО для массива опциональных интов // не использовать функции высшего порядка Ответ:

extension Array where Element == Int? {

    func compactMapForInt() -> [Int] {
        var result: [Int] = []
        for i in self {
            if i != nil {
                result.append(i)
            }
        }
        return result
    }
}

Теперь нужно сделать так, чтобы compactMap() принимала также массив [Int?], но возвращать должна массив заданного типа, допустим [Int] или [NilAnalyzer], либо еще че- то. Вот так:

et integerArray = [1,2,nil,4,nil] var mappedArray = integerArray.compactMap -> [true, true, false, true, false] // struct NilAnalyzer { let isNil: Bool } mappedArray = integerArray.compactMap -> [NilAnalyzer(isNil: false), NilAnalyzer(isNil: false), NilAnalyzer(isNil: true)...]

Ответ:

extension Array {
    func compactMap<T>(_ transform: (Element) -> T?) -> [T] {
        var result: [T] = []
        for value in self {
            if let transformedValue = transform(value) {
                result.append(transformedValue)
            }
        }
        return result
    }
}

let integerArray: [Int?] = [1, 2, nil, 4, nil]

// Использование для преобразования nil в true и ненулевых значений в false
let booleanArray = integerArray.compactMap { value -> Bool? in
    return value == nil ? true : false
}

print(booleanArray) // [false, false, true, false, true]

// Структура NilAnalyzer
struct NilAnalyzer {
    let isNil: Bool
}

// Использование для преобразования nil в NilAnalyzer(isNil: true) и ненулевых значений в NilAnalyzer(isNil: false)
let nilAnalyzerArray = integerArray.compactMap { value -> NilAnalyzer? in
    return NilAnalyzer(isNil: value == nil)
}

print(nilAnalyzerArray) // [NilAnalyzer(isNil: false), NilAnalyzer(isNil: false), NilAnalyzer(isNil: true), NilAnalyzer(isNil: false), NilAnalyzer(isNil: true)]

Задача 5.

var elements = [1,2,3]
for e in elements {
    print(e)
    elements = [4,5,6]
}

Вопрос: что выведет print и почему. Ответ: 123 – т.к. elements поменяется на [4, 5, 6], но цикл for использует копию массива для итерации

Задача 6.

class A {
    var a: A?
}

struct B {
    var b: [B]?
}

struct C {
    var c: C?
}

Вопрос: Где и почему компилятор выведет ошибку. Ответ: struct C — структуры не могут содержать внутри себя прямых или опциональных экземпляров самих себя, так как это приводит к бесконечной рекурсии при инициализации. Нужно либо заменить на class, либо сделать var c: C?

Задача 7.

class C {
    var text: String = "1"
}

var value: C? = C()
var strongValue: C? = value
value?.text = "2"

let closure = {
    value?.text = "3"
}
value = nil

closure()

if let text = strongValue?.text {
    print(text)
} else {
    print("nil")
}

Вопрос: Что происходит. Ответ: 2. Имеем два свойства: strongValue и value – они оба указывают на один и тот же объект класса C. После value?.text = 2 свойство text этого объекта становится 2. Потом value делаем nil (но не делаем nil объект, на который он ссылается), т.е. сам объект остается, т.к. strongValue все еще указывает на него. Выполняется кложура, но text не поменяется, т.к. value == nil. Итого получаем что strongValue, ссылающегося на объект класса C, где text == 2. Print выведет 2.

Задача 8.

let newView = UIView(frame: CGRect(x: 100, y: 100, width: 100, height: 100))
newView.backgroundColor = .red

newView.layer.bounds.size = CGSize(width: 30, height: 30)
// 1. Что будет на экране?
// 2. Что выведет print(newView.frame)?

Ответ: На экране будет отображаться красный квадрат с размерами 30×30. Само UIView останется с frame 100 x 100. Поэтому print выведет (100.0, 100.0, 100.0, 100.0). layer.bounds.size изменяет размеры отображаемого контента без изменения положения и размеров самого представления (UIView). Фрейм UIView представляет собой его положение и размер относительно суперпредставления. Изменение layer.bounds.size не изменяет фрейм самого представления, а изменяет только размеры его содержимого.

Задача 9.

let newView = UIView(frame: CGRect(x: 100, y: 100, width: 100, height: 100))
UIView.animate(withDuration: 5) {
    self.newView.frame = CGRect(x: 100, y: 600, width: 100, height: 100)
}
// Что выведет, если вызовем через 2.5 сек? print(newView.frame)

Ответ: (100.0, 6000.0, 100.0, 100.0). «Презентационный» слой и «модальный» — разные. Свойство меняется сразу на итоговое, хоть анимируется и плавное изменение.

Задача 10.

///
let newView = UIView(frame: CGRect(x: 100, y: 100, width: 100, height: 100))
UIView.animate(withDuration: 5) {
    self.newView.frame = CGRect(x: 100, y: 600, width: 100, height: 100)
}
// Что выведет, если вызовем через 2.5 сек? sleep(10)

Ответ: через 2.5 с. Анимация заморозится, через еще 10 с. продолжится и закончится мгновенно. Тут можно почитать, но вроде бы так должно быть.

Задача 11. Вопрос: Какие методы для обновления коллекции, как обновить без анимации и т.п. Ответ:  colletionView.reloadSections(IndexSet(integer: 0)) – перезагрузка секции;  CATransaction – для группировки операций. В примере ниже все изменения слоя, которые происходят между CATransaction.begin() и CATransaction.commit(), будут сгруппированы, и когда все анимации завершатся, вызовется блок, заданный в CATransaction.setCompletionBlock

CATransaction.begin() CATransaction.setCompletionBlock { // Код, который выполнится после завершения всех анимаций в этой транзакции } CATransaction.commit()

UIView.perforwithoutanimation { } – выполяет визуальные изменения мгновенно, без анимаций.

Задача 12.

class People {
    var name: String = "Bill"

    func sayHello() {
        doAction {
            print("Hello my name is (self.name)")
        }
    }

    private func doAction(closure: @escaping () -> Void) {
        DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
            closure()
        }
    }

    deinit {
        print("People deiniting")
    }
}

var people: People? = People()
people?.sayHello()
people = nil

Вопрос: Что выведет и почему. Ответ: Hello my name is Bill People deiniting Выполняется sayHello, принтится «Hello my name is Bill», экземпляр people становится nil, но экземпляр People, на который ссылался people, не деинитится, т.к. его держит сильная ссылка на self в замыкании, и по этому же после 1 сек отложенное замыкание будет выполнено, после чего экземпляр People ничего не держит, и происходит деинит. Тут могут доспросить че будет если [weak self] добавить и почему.

Задача 13. Вопрос: че будет

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)
}

Вопрос: че будет Ответ: 8 1 2 3 4 5 6 потом упадет из-за serial.sync { print(7) } на уже serial.sync { … } Как исправить (не делать sync на синхр. очереди).

Задача 14.

var count = 0 // 2000
let group = DispatchGroup()
let countQueue = DispatchQueue(label: "countQueue", attributes: .concurrent)

group.enter()
let thread1 = Thread {
    for _ in 0...999 {
        countQueue.async(flag: .barrier) {
            count += 1
        }
    }
    group.leave()
}

group.enter()
let thread2 = Thread {
    for _ in 0...999 {
        countQueue.async(flag: .barrier) {
            count += 1
        }
    }
    group.leave()
}

thread1.start()
thread2.start()

group.notify(queue: .global()) {
    print(count)
}

Выделил красным то что дописал. Там была проблема с одновременным обращением к счетчику с разных потоков. Ответ: В целом рассказать в двух словах про группы, очереди, барьер.