Используйте разные конфигурации 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:).