Назад к задачамПолучайте помощь с лайвкодингом в реальном времени с Sobes Copilot
Junior — Senior
6
Оптимизация экрана загрузки списка пользователей
Компании, где спрашивали:
SmartWay
Условие задачи
Модуль реализован как экран с ползунком для выбора количества запрашиваемых пользователей, кнопкой для инициирования загрузки и несколькими представлениями для отображения результата. Полный список выводится полностью, без постраничной подгрузки.
Требуется изучить текущую реализацию и исправить все найденные недочёты.
struct ContentView: View {
@ObservedObject private var vm = ViewModel()
@State private var userCount = 3.0
var body: some View {
ZStack(alignment: .top) {
Background(count: $userCount)
.frame(width: UIScreen.main.bounds.width, height: 115)
VStack {
Slider(
value: $userCount,
in: 3...100,
step: 1
) { _ in }
.tint(.purple)
Button("Запросить \(Int(userCount)) пользователей") {
Task {
await vm.downloadNames(count: Int(userCount))
}
}
.padding()
.foregroundStyle(.white)
.background(.purple)
.clipShape(.buttonBorder)
ProxyView(viewModel: vm)
}
}
}
}
struct Background: View {
@Binding var count: Double
var backgroundColor: Color {
switch count {
case ..<10: return .green
case 10..<50: return .yellow
default: return .red
}
}
var body: some View {
Rectangle()
.fill(backgroundColor)
}
}
struct ProxyView: View {
@ObservedObject var viewModel: ViewModel
var body: some View {
SuccessView(viewModel: viewModel)
}
}
struct SuccessView: View {
@ObservedObject var viewModel: ViewModel
@State private var loading: Bool = false
var body: some View {
VStack {
Text("Total users fetched: \(viewModel.names.count)")
if loading { ProgressView() }
List(viewModel.names, id: \ .self) { name in
Text(name)
}
}
.onReceive(viewModel.publisher) { value in
loading = value
}
}
}
class ViewModel: ObservableObject {
let networkService = NetworkService()
let value = CurrentValueSubject<Bool, Never>(false)
@Published var names: [String] = []
var publisher: AnyPublisher<Bool, Never> {
value.eraseToAnyPublisher()
}
func downloadNames(count: Int) async {
value.send(true)
async let ids = networkService.fetchUserIds(count: count)
for id in await ids {
networkService.fetchName(id: id) { name in
self.names.append(name)
}
}
value.send(false)
}
}
class NetworkService {
func fetchName(id: Int, completion: @escaping (String) -> Void) {
let names = ["Александр", "Максим", "Иван", "Артём", "Дмитрий", "Никито", "Михаил", "Даниил", "Егор"]
let surnames = ["Смирное", "Иванов", "Кузнецов", "Соколов", "Попов", "Лебедев", "Козлов", "Новиков", "Морозов"]
DispatchQueue.global(qos: .utility).asyncAfter(deadline: .now() + 1) {
completion(names.randomElement()! + " " + surnames.randomElement()!)
}
}
func fetchUserIds(count: Int) async -> [Int] {
try? await Task.sleep(for: .seconds(1))
return Array(1...count)
}
}
# Preview {
ContentView()
}