Список контактов
1. Функциональные требования по заданию.
1.1 Экран со списком контактов выполнен по дизайну и строго по заданию.
1.2 Экран добавления контакта
- Плейсхолдер в avatarImageView не соответствует дизайну.
- При активации нижнего текстового поля клавиатура закрывает его, не происходит скролла.
- Экран создания нового контакта не закрывается.
- Новый контакт сохраняется через раз.
- В текстовом поле Notes, есть toolbar, хотя он не нужен.
- В поле Ringtone нет disclosure индикатора.
- Поиск не работает.
- После деактивации поиска таблица не обновляется и данные не возвращаются.
- Если создать пользователя без имени, то вместо имени будет пробел.
- Можно создавать пустых пользователей.
- Если написать слишком длинные имена, то не происходит переноса. Всё в одну строку, ограничений нет
2. Реализация
- Необходимо передавать window в coordinator и настраивать уже там, просто вызывав метод координатора start.
- Нет единого порядка в коде. Всё в разнобой, сложно читать.
- Много закомментированного лишнего кода.
- Методы настройки views называются setupLayout. Корректней называть setupViews.
- Как и во всех проектах до, многие свойства без указания видимости. Многие публичные, там где это не нужно.
- AddContact и Edit viewControllers это два разных экрана. Должен использоваться один. Они почти не отличаются друг от друга. Происходит копирование кода
- Настройка window происходит в SceneDelegate. Как и писал в проектах ранее, это должно происходить в MainCoordinator
- MainCoordinator управляет всей навигацией. У модуля ContactDetailsViewController должен быть свой координатор
- extension UIImage+Data создаёт лишний код, который не создаёт никакой полезности
- extension UINavigationController - из названия непонятно что расширяется. Также зачем вообще нужно менять transition UINavigationController. В задании этого не было + дефолтные хорошо бы справились с задачей.
- Многие поля указаны как обязательные для заполнения, но пользователь никогда не узнает об этом.
- Файлы разбросаны по проекту и лежат не в тех корнях, где должны
3. Экран списка контактов
3.1 ContactsViewController
- contactIndexTitles массив должен быть вынесен во viewModel или константу.
- На протокол UITableViewDataSource в идеале должен подписываться отдельный класс, а не viewController, в таком случае можно будет переиспользовать класс.
- viewController подготавливает данные для себя, такого быть не должно. Это должна делать viewModel.
- Есть force unwraps, вместо них должна быть проверка guard/if let.
- Не совсем верный порядок вызова методово настройки viewController. Сейчас запрашиваются данные у viewModel, затем настраивается viewController и его subviews. В таком случае невозможно показать загрузку. И если запрос будет выполняться долго, пользователь будет смотреть в белый экран.
- Также неверный порядок в том, что тут запрашиваются данные у viewModel, а только потом происходит binding. Необходимо вначале подписаться, только потом запрашивать.
- В методе viewWillAppear происходит обновление таблицы. То есть каждый раз когда происходит показ экрана обновляется таблица. Обновлять нужно только в том случае, если данные изменились.
3.2 ContactsViewModel
- Непонятно название структуры Model, что она значит и почему не в отдельном файле.
- Не совсем корректные методы делегата ContactsViewModelDelegate(addContact). Необходимо придерживаться стиля Apple.
Например: func contactsViewModelDidRequestAddContact(_ viewModel: ContactsViewModel).
- Есть forceUnwrap, нужно добавлять проверки guard/if let.
- Данные из БД обрабатываются в dictionary с которым сложно работать, нужно обернуть это всё в структуру.
3.3 ContactsTableViewCell
- Неверное название ячейки. ContactTableViewCell - так как она отображает один контакт а не много
- identifier указан обычной строкой. Так делаеть нельзя, если переименовать файл, то можно забыть про identifier и всё сломается.
Лучше так: let identifier = String(describing: ContactsTableViewCell.self)
- Все subviews в ячейке публичные
- Все subviews в ячейке var, должно быть let
- Constraints можно было выставить чуть проще, а не писать каждую сторону.
Например:
firstNameLabel.snp.makeConstraints { make in
make.leading.trailing.bottom.equalToSuperview().inset(16)
}
4. Детали контакта
4.1 ContactDetailsViewController
- StretchyTableHeaderView не используется нигде.
- Есть UITableView, который не используется в коде.
- Не понятно зачем разделители (divider1, divider2, divider3) во viewController, если они есть в ContactDetailsView.
- ContactDetailsView слишком общее название. Из него непонятно что это за view.
- Все subviews добавляются одна за другой на view самого viewController, лучше вместо этого создать stackView и добавлять subviews туда. Получилось бы проще и короче.
- Настройка всех view просиходит в одном методе. Нужно каждую view настраивать в отдельном методе, а уже в setup вызывать эти методы.
- viewModel не подготавливает данные, а лишь отдаёт контакт. Так быть не должно.
4.2 ContactDetailsViewModel
- Неверное именование методов делегата. Уже писал выше об этом.
- viewModel тут бесполезна и ничего не делает по сути
5. Создание контакта
5.1 AddContactViewController
- Массива ringtones не должно быть во viewController
- Много текстовых полей, которые лучше было вынести в отдельные view с разными настройками текста
- dividers также нужно было вынести в те view где лежали бы текстовые поля
- В контроллере происходит работа с БД, этим должна заниматься viewModel
- viewController занимается навигацией, этим должен заниматься кординатор
- Много строк, которые не вынесены в отдельные файлы локализации
- Есть общий метод setupLayout где настраиваются subviews и во viewDidLoad вызываются отдельные методы, где настраиваются subviews
- Очень огромный класс получился, который всем управляет. За то AddContactViewModel также бесполезна как и ContactDetailsViewModel. По ней не буду ничего отписывать
6. Редактирование контакта
По этому модулю не буду отписывать, так как это копипаста AddContactViewController. Повторюсь, что нужно было использовать один viewController
7. CoreDataManager
- Нет обработок ошибок
- Много forceUnwrap