Skip to content

Review#1

Open
aniramskaya wants to merge 2 commits intoemptyfrom
main
Open

Review#1
aniramskaya wants to merge 2 commits intoemptyfrom
main

Conversation

@aniramskaya
Copy link
Owner

No description provided.

Comment on lines +9 to +11
static var xBeforeAnimation: CGFloat = 0
static var xAfterAnimation: CGFloat = 0
static var isButtonShow = false
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Эти переменные лучше сделать свойствами самого OverviewListViewController. Если enum называется Constants, то очевидно в него стоит помещать только константы.

isButtonShow - не очень удачный нейминг, звучит не по-английски. Можно заменить на isButtonVisible или shouldDisplayButton.
Еще о нейминге: offsetForButton станет понятнее, если заменить на buttonOffset. Предлоги лучше стараться не использовать в названиях. Это не железобетонное правило, но в большинстве случаев можно обойтись без них.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

переменные сделать свойствами VC - ✔

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Оно конечно очевидно, и была идея создать enum Variables {} Х). Про переменные лучше сделать свойствами - я запомню.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

isButtonVisible - ✔

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

buttonOffset - ✔ . Предлоги лучше стараться не использовать в названиях - взял на заметку.
rowHeight , buttonHeight - ✔

static var isButtonShow = false
}

private var array = [1]
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Слишком общее название свойства. Из него непонятно что в этом массиве хранится.

Для массивов лучше явно задавать их тип, чтобы человек, читающий код не напрягался вычислением типа. Например вот так:
private var randomNumbers: [Int] = []

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

private var notesArray: Results = RealmManager.shared.fetchData() - ✔

Comment on lines +16 to +23
private let createNoteButton: UIButton = {
let button: UIButton = .init()
button.setImage(UIImage(named: "pencil"), for: .normal)
button.backgroundColor = .none
button.bounds.size = .init(width: 50, height: 50)
button.addTarget(self, action: #selector(createNoteButtonPressed), for: .touchUpInside)
return button
}()
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Вспомогательный код можно попробовать вынести в private extension. Много строк вспомогательного кода засоряет основной код и расфокусирует внимание читающего.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

вынести в private extension - ✔


override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
Constants.isButtonShow ? setXForButton(x: Constants.xAfterAnimation) : setXForButton(x: Constants.xBeforeAnimation)
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Мне кажется, это не очень удачное место для изменения положения кнопки. Что если изменение положения вызовет новый layout pass? Можно сделать отдельный метод updateCreateNoteButton и вызывать его там, где менятся isButtonShow или, если бы isButtonShow был свойством контроллера, то можно было бы навесить на него обсервер:

private var isButtonShow = false {
    didSet { updateCreateNoteButton() }
}

Еще такой момент с неймингом: если кнопка называется createNoteButton то и все остальные сущности, которые имеют к ней отношение, должны называться похожим образом. Например, можно так переименовать:

isButtonShow -> isCreateNoteButtonVisible
setXForButton -> setXForCreateNoteButton
startButtonAnimation -> startCreteNoteButtonAnimation

}

private func startButtonAnimation () {
UIView.animate(withDuration: 0.4, delay: 0.3) { [self] in
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Магические константы

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment on lines +70 to +72
private func setXForButton (x: CGFloat) {
createNoteButton.frame.origin.x = x
}
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Как-то много танцев с бубном вокруг одной кнопки в этом контроллере. Как я поняла, она должна анимированно отображаться на экране сразу после появления контроллера на экране и неанимированно скрываться при переходе на другой экран.
Можно просто сделать пару методов displayCreateNoteButtonAnimated и hideCreateNoteButton, которые и вызывать в нужных местах.

}

@objc private func createNoteButtonPressed() {
array.append(Int.random(in: 11...222))
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

Copy link
Collaborator

@AlekseiBodrov AlekseiBodrov Dec 25, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Строчку удалил - была заглушкой. - ✔

Comment on lines +97 to +98
guard let controller = self.storyboard?.instantiateViewController(withIdentifier: "EditingViewController") as? EditingViewController else { return }
self.navigationController?.pushViewController(controller, animated: true)
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Эти две строчки тоже достойны выноса в отдельный метод.

Copy link
Collaborator

@AlekseiBodrov AlekseiBodrov Dec 25, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✔ . Я держал это в голове, но лучше сразу править - если увидел кривоту - по моему это как раз слова дяди Боба.

var isAnyButtonPressed = false

//Нужен для передачи данных между контроллерами
var noteData: ((_ contentNote: NSMutableAttributedString,_ dateCreateNote: Date, IndexPath?) -> Void)?
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Для хранения данных лучше сделать модель. IndexPath - это детали реализации соседнего контроллера, они не должны просачиваться в модель. Что это означает? IndexPath - это одна из особенностей работы UITableView. Появление этой информации в модели или соседнем контроллере прибивает гвоздями существование таблицы в OverviewListViewController - замена в нем UITableView на UIStackView (например) вызовет много боли и потенциальных багов. Кроме того, заметка вовсе не ответственна за свое положение в списке, поэтому такая информация должна храниться на уровне списка, а не заметки.


override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
configure()
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Кажется, вызов configure лучше перенести в viewDidLoad. Здесь configure будет вызываться каждый раз когда контроллер появляется на экране. После перехода в контроллер выбора изображений и возврата обратно configure вызовется еще раз, панель с кнопками создастся заново и снова добавится в иерархию UI.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✔ Даже странно что configure оказался во viewDidAppear, скорее всего поторопился и промахнулся. Согласен configure достаточно сделать один раз за жизнь ViewController-а

override func viewDidDisappear(_ animated: Bool) {
super.viewDidDisappear(animated)
let dateCreate = Date()
noteData?(NSMutableAttributedString.init(attributedString: textNoteTextView.attributedText), dateCreate, indexPath)
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Интересно, зачем здесь потребовался именно NSMutableAttributedString?

Comment on lines +55 to +58
deinit {
NotificationCenter.default.removeObserver(self, name: UIResponder.keyboardWillShowNotification, object: nil)
NotificationCenter.default.removeObserver(self, name: UIResponder.keyboardWillHideNotification, object: nil)
}
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Отлично что позаботился об отписке от уведомлений!
Можно одной строкой отписаться сразу от всех:
NotificationCenter.default.removeObserver(self)

Надо внимательно посмотреть - имеет ли смысл контроллеру получать эти уведомления, когда он, например, скрыт каким-то модальным контроллером, у которого есть поле ввода и тоже выезжает клавиатура. Если в этом нет необходимости, то можно подписываться, когда контроллер появляеся на экране и отписываться когда он исчезает с экрана.

Comment on lines +104 to +112
func getTextForNote() {
if isOldNote, indexPath != nil {
// let note = dataStoreManager.fetchResultController.object(at: indexPath!)
// textNoteTextView.attributedText = note.content
} else {
textNoteTextView.text = ""
addAttributesInTextView()
}
}
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Несмотря на то, что код закомментирован, хочу заметить что лучше избегать косвенной передачи данных. Получается, контроллер должен куда-то сходить за данными, с которыми ему нужно работать. Он становится сильно зависим от источника данных. Этой зависимости не будет, если тот, кто инициирует вывод этого контроллера на экран, сразу передаст ему все необходимые данные.

Comment on lines +141 to +142
let fontDescriptor = UIFontDescriptor.preferredFontDescriptor(withTextStyle: .body)
let boldFontDescriptor = fontDescriptor.withSymbolicTraits(.traitBold)
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Эти дескрипторы используются повсюду, их можно вынести в константы или в методы приватного расширения.

Comment on lines +144 to +145
let boldFont = UIFont(descriptor: boldFontDescriptor!, size: 24)
let normalFont = UIFont(descriptor: fontDescriptor, size: 20)
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Можно вынести в приватное расширение не только дескрипторы, но и создание шрифтов. Будем в каждый из методов передавать только размер шрифта:

let boldFont = makeBoldFont(size: 24)
let normalFont = makeNormalFont(size: 24)

И пусть дескрипторы останутся скрыты внутри этих методов.

Comment on lines +148 to +149
let firstParagraph = textStorage.mutableString.paragraphRange(for: NSRange(location: 0, length: 0))
let otherParagraphs = NSString(string: getNoteContent(text: textNoteTextView.text))
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Тут надо подумать как убрать несимметричность. firstParagraph имеет тип NSRange, а otherParagraphs - это String. Легко перепутать. Если несимметричность не убрать или нет смысла ее убирать, то нужно скорректировать названия переменных, чтобы было понятно.

}
}

@objc func reducineTheFontSize() {
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Опечатка: reducineTheFontSize -> reduceTheFontSize

}
}
}

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

В целом, как заметно улучшить код этого контроллера. Все методы, оперирующие текстом можно вынести в отдельную сущность, которой при создании передать textNoteTextView.textStorage. Для того, чтобы подсвечивать кнопки, можно сделать ей свойство (или просто набор булевых свойств), которое будет показывать какие кнопки нужно подсветить. Код контроллера за счет такого изменения сильно разгрузится и станет намного более читабельным. Логика будет отделена от UI, что очень и очень хорошо.

Вместо изменения backgroundColor кнопок можно использовать setBackgroundImage(UIImage?, for: UIControl.State) и просто переключать состояние isHighlighted у кнопок. UIImage можно сгенерировать программно с нужными цветами.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants