Реализовать клиент аналитики с выводом в консоль и записью в файл

Используйте разные конфигурации AnalyticsClient: для первого экрана — console sink, для второго — console и file sink. Запись файла сериализуйте общей очередью.

Короткий ответ

Что ответить на собеседовании

Используйте разные конфигурации AnalyticsClient: для первого экрана — console sink, для второго — console и file sink. Запись файла сериализуйте общей очередью.

Подробный разбор

Ответ с пояснениями

Условие

Требуется обеспечить работу сервиса аналитики так, чтобы он мог выводить события в консоль, а также сохранять их в файл на втором экране.

public struct AnalyticsEvent {
    public var name: String
    public var params: [String: String]

    public init(name: String, params: [String: String]) {
        self.name = name
        self.params = params
    }
}

public final class AnalyticsClient {
    public func report(_ event: AnalyticsEvent) { ... }
}
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: [:]))
    }
}
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: [:]))
    }
}

Ваша задача – дополнить реализацию AnalyticsClient так, чтобы при вызове report(_:) событие выводилось в консоль, а при работе экрана 2 дополнительно записывалось в файл. Нужно продумать, где хранить путь к файлу, как открывать/закрывать его и обеспечить потокобезопасность, если клиент будет использоваться из разных потоков.

Ответ

Используйте разные конфигурации AnalyticsClient: для первого экрана — console sink, для второго — console и file sink. Запись файла сериализуйте общей очередью.

Ключевой контракт можно представить так:

protocol AnalyticsSink { func write(_ event: AnalyticsEvent) }
final class AnalyticsClient {
    private let sinks: [any AnalyticsSink]
    init(sinks: [any AnalyticsSink]) { self.sinks = sinks }
    func report(_ event: AnalyticsEvent) {
        for sink in sinks { sink.write(event) }
    }
}

ConsoleSink печатает очищенные поля; FileSink на своей serial queue открывает файл для append, пишет одну JSONL-запись и закрывает handle через defer. Один файл должен иметь одного владельца очереди даже при нескольких клиентах. URL каталога приложения внедряется в FileSink; нужны ротация, лимит размера и обработка ошибок записи. Не используйте глобальный флаг «сейчас экран 2». В контроллерах исправьте сигнатуры viewDidAppear(_:), объявите analytics, вызовите super.init и реализуйте required init(coder:).

ИИ-помощник для собеседований

Хочешь уверенно проходить собеседования?

Попробуй ИИ-помощник для собеседований: слышит вас и собеседника, анализирует экран, подсказывает ответы в реальном времени, работает без VPN и не попадает в захват экрана.

Подробнее