
рдирдорд╕реНрдХрд╛рд░, рд╣реЗрдмреНрд░!
рдореЗрд░рд╛ рдирд╛рдо рд╡рд▓реЗрд░рд╛ рд╣реИ, рдФрд░ рдЕрдм рджреЛ рд╕рд╛рд▓ рд╕реЗ рдореИрдВ рдПрдХ iOS рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдХреЛ рд╡рд┐рдХрд╕рд┐рдд рдХрд░ рд░рд╣рд╛ рд╣реВрдВ, рдЬреЛ рдХрд┐ рдЯреАрдо рдХрд╛ рд╣рд┐рд╕реНрд╕рд╛ рд╣реИред рд╣рдорд╛рд░реА рдкреНрд░рд╛рдердорд┐рдХрддрд╛рдУрдВ рдореЗрдВ рд╕реЗ рдПрдХ рдХреЛрдб рдХреЛ рдмрдирд╛рдП рд░рдЦрдирд╛ рдЖрд╕рд╛рди рд╣реИред рд╕рд╛рдкреНрддрд╛рд╣рд┐рдХ рд░реВрдк рд╕реЗ рд╣рдорд╛рд░реЗ рд╣рд╛рдереЛрдВ рдореЗрдВ рдЖрдиреЗ рд╡рд╛рд▓реА рдирдИ рд╕реБрд╡рд┐рдзрд╛рдУрдВ рдХреА рдмрдбрд╝реА рд╕рдВрдЦреНрдпрд╛ рдХреЗ рдХрд╛рд░рдг, рд╣рдореЗрдВ рдкрд╣рд▓реЗ рдЖрд╡реЗрджрди рдХреА рд╡рд╛рд╕реНрддреБрдХрд▓рд╛ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рд╕реЛрдЪрдирд╛ рд╣реЛрдЧрд╛, рдЕрдиреНрдпрдерд╛ рдореМрдЬреВрджрд╛ рд╡рд┐рд╢реЗрд╖рддрд╛рдУрдВ рдХреЛ рддреЛрдбрд╝реЗ рдмрд┐рдирд╛ рдЙрддреНрдкрд╛рдж рдореЗрдВ рдПрдХ рдирдИ рд╕реБрд╡рд┐рдзрд╛ рдЬреЛрдбрд╝рдирд╛ рдмреЗрд╣рдж рдореБрд╢реНрдХрд┐рд▓ рд╣реЛрдЧрд╛ред рдЬрд╛рд╣рд┐рд░ рд╣реИ, рдпрд╣ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдЗрдВрдЯрд░рдлрд╝реЗрд╕ (UI) рдХреЗ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рдкрд░ рднреА рд▓рд╛рдЧреВ рд╣реЛрддрд╛ рд╣реИ, рднрд▓реЗ рд╣реА рдпрд╣ рдХреЛрдб, Xcode (XIB) рдпрд╛ рдорд┐рд╢реНрд░рд┐рдд рджреГрд╖реНрдЯрд┐рдХреЛрдг рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдХрд┐рдпрд╛ рдЧрдпрд╛ рд╣реЛред рдЗрд╕ рд▓реЗрдЦ рдореЗрдВ рдореИрдВ рдХреБрдЫ рдпреВрдЖрдИ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рддрдХрдиреАрдХреЛрдВ рдХрд╛ рд╡рд░реНрдгрди рдХрд░реВрдВрдЧрд╛ рдЬреЛ рд╣рдореЗрдВ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдЗрдВрдЯрд░рдлрд╝реЗрд╕ рдХреЗ рд╡рд┐рдХрд╛рд╕ рдХреЛ рд╕рд░рд▓ рдмрдирд╛рдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рджреЗрддреЗ рд╣реИрдВ, рдЬрд┐рд╕рд╕реЗ рдпрд╣ рдкрд░реАрдХреНрд╖рдг рдХреЗ рд▓рд┐рдП рд▓рдЪреАрд▓рд╛ рдФрд░ рд╕реБрд╡рд┐рдзрд╛рдЬрдирдХ рд╣реЛ рдЬрд╛рддрд╛ рд╣реИред рдЗрд╕ рд▓реЗрдЦ рдХрд╛ рдПрдХ
рдЕрдВрдЧреНрд░реЗрдЬреА рд╕рдВрд╕реНрдХрд░рдг рднреА рд╣реИред
рд╢реБрд░реВ рдХрд░рдиреЗ рд╕реЗ рдкрд╣рд▓реЗ ...
рдореИрдВ рд╕реНрд╡рд┐рдлреНрдЯ рдореЗрдВ рд▓рд┐рдЦреЗ рдЧрдП рдПрдХ рдЙрджрд╛рд╣рд░рдг рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдЗрдВрдЯрд░рдлрд╝реЗрд╕ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рддрдХрдиреАрдХреЛрдВ рдкрд░ рд╡рд┐рдЪрд╛рд░ рдХрд░реВрдВрдЧрд╛ред рдПрдХ рдмрдЯрди рдкрд░ рдХреНрд▓рд┐рдХ рдХрд░рдиреЗ рдкрд░ рдЖрд╡реЗрджрди рджреЛрд╕реНрддреЛрдВ рдХреА рдПрдХ рд╕реВрдЪреА рджрд┐рдЦрд╛рддрд╛ рд╣реИред
рдЗрд╕рдореЗрдВ рддреАрди рднрд╛рдЧ рд╣реЛрддреЗ рд╣реИрдВ:
- рдШрдЯрдХ рдХрд╕реНрдЯрдо UI рдШрдЯрдХ рд╣реИрдВ, рдЕрд░реНрдерд╛рддреН, рдХреЛрдб рдХреЗрд╡рд▓ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдЗрдВрдЯрд░рдлрд╝реЗрд╕ рд╕реЗ рд╕рдВрдмрдВрдзрд┐рдд рд╣реИред
- рдбреЗрдореЛ рдПрдкреНрд▓рд┐рдХреЗрд╢рди - рдбреЗрдореЛ рд╡реНрдпреВ рдореЙрдбрд▓ рдФрд░ рдЕрдиреНрдп рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдЗрдВрдЯрд░рдлрд╝реЗрд╕ рдЗрдХрд╛рдЗрдпрд╛рдВ рдЬрд┐рдирдХреЗ рдкрд╛рд╕ рдХреЗрд╡рд▓ рдпреВрдЖрдИ рдирд┐рд░реНрднрд░рддрд╛рдПрдВ рд╣реИрдВред
- рд╡рд╛рд╕реНрддрд╡рд┐рдХ рдЕрдиреБрдкреНрд░рдпреЛрдЧ рджреГрд╢реНрдп рдореЙрдбрд▓ рдФрд░ рдЕрдиреНрдп рдЗрдХрд╛рдЗрдпрд╛рдБ рд╣реИрдВ рдЬрд┐рдирдореЗрдВ рд╡рд┐рд╢рд┐рд╖реНрдЯ рдирд┐рд░реНрднрд░рддрд╛ рдФрд░ рддрд░реНрдХ рд╣реЛ рд╕рдХрддреЗ рд╣реИрдВред
рдРрд╕рд╛ рдЕрд▓рдЧрд╛рд╡ рдХреНрдпреЛрдВ рд╣реИ? рдореИрдВ рдиреАрдЪреЗ рдЗрд╕ рдкреНрд░рд╢реНрди рдХрд╛ рдЙрддреНрддрд░ рджреВрдВрдЧрд╛, рд▓реЗрдХрд┐рди рдЕрднреА рдХреЗ рд▓рд┐рдП, рд╣рдорд╛рд░реЗ рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдХреЗ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдЗрдВрдЯрд░рдлрд╝реЗрд╕ рдХреЛ рджреЗрдЦреЗрдВ:
рдпрд╣ рдПрдХ рдкреВрд░реНрдг-рд╕реНрдХреНрд░реАрди рджреГрд╢реНрдп рдХреЗ рд╢реАрд░реНрд╖ рдкрд░ рд╕рд╛рдордЧреНрд░реА рдХреЗ рд╕рд╛рде рдПрдХ рдкреЙрдк-рдЕрдк рджреГрд╢реНрдп рд╣реИред рд╕рдм рдХреБрдЫ рд╕рд░рд▓ рд╣реИред
рдкрд░рд┐рдпреЛрдЬрдирд╛ рдХрд╛ рдкреВрд░реНрдг рд╕реНрд░реЛрдд рдХреЛрдб
GitHub рдкрд░ рдЙрдкрд▓рдмреНрдз
рд╣реИ ред
рдпреВрдЖрдИ рдХреЛрдб рдореЗрдВ рджреЗрд░реА рдХрд░рдиреЗ рд╕реЗ рдкрд╣рд▓реЗ, рдореИрдВ рдЖрдкрдХреЛ рдпрд╣рд╛рдВ рдЙрдкрдпреЛрдЧ рдХрд┐рдП рдЬрд╛рдиреЗ рд╡рд╛рд▓реЗ рд╕рд╣рд╛рдпрдХ рд╡рд░реНрдЧ рдХреЗ рд▓рд┐рдП рдкрд░рд┐рдЪрдп рджреЗрдирд╛ рдЪрд╛рд╣рддрд╛ рд╣реВрдВред рдЗрд╕рдХрд╛ рдЗрдВрдЯрд░рдлрд╝реЗрд╕ рдЗрд╕ рддрд░рд╣ рджрд┐рдЦрддрд╛ рд╣реИ:
var value: T func observe(_ closure: @escaping (_ old: T, _ new: T) -> Void) -> ObserverProtocol func observeNewAndCall(_ closure: @escaping (_ new: T) -> Void) -> ObserverProtocol
рдпрд╣ рдХреЗрд╡рд▓ рдкрд░рд┐рд╡рд░реНрддрдиреЛрдВ рдХреЗ рд╕рднреА рдкрд╣рд▓реЗ рд╕реЗ рд╣рд╕реНрддрд╛рдХреНрд╖рд░ рдХрд┐рдП рдЧрдП рдкрд░реНрдпрд╡реЗрдХреНрд╖рдХреЛрдВ рдХреЛ рд╕реВрдЪрд┐рдд рдХрд░рддрд╛ рд╣реИ, рдЗрд╕рд▓рд┐рдП рдпрд╣ рдХреЗрд╡реАрдУ (рдХреБрдВрдЬреА-рдореВрд▓реНрдп рдХрд╛ рдЕрд╡рд▓реЛрдХрди) рдХрд╛ рдПрдХ рдкреНрд░рдХрд╛рд░ рд╣реИ рдпрд╛, рдпрджрд┐ рдЖрдк рдЪрд╛рд╣реЗрдВ, рддреЛ рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛рд╢реАрд▓ рдкреНрд░реЛрдЧреНрд░рд╛рдорд┐рдВрдЧред рдпрд╣рд╛рдБ рдПрдХ рдЙрдкрдпреЛрдЧ рдЙрджрд╛рд╣рд░рдг рд╣реИ:
self.observers.append(self.viewModel.items.observe { [weak self] (_, newItems) in self?.state = newItems.isEmpty ? .zeroCase(type: .empty) : .normal self?.collectionView.reloadSections(IndexSet(integer: 0)) })
рдирд┐рдпрдВрддреНрд░рдХ
self.viewModel.items
рдЧреБрдг рдореЗрдВ рдкрд░рд┐рд╡рд░реНрддрди рдХреА рд╕рджрд╕реНрдпрддрд╛ рд▓реЗрддрд╛ рд╣реИ, рдФрд░ рдЬрдм рдкрд░рд┐рд╡рд░реНрддрди рд╣реЛрддрд╛ рд╣реИ, рддреЛ рд╣реИрдВрдбрд▓рд░ рд╡реНрдпрд╛рд╡рд╕рд╛рдпрд┐рдХ рддрд░реНрдХ рдХреЛ рдирд┐рд╖реНрдкрд╛рджрд┐рдд рдХрд░рддрд╛ рд╣реИред рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рдпрд╣ рджреГрд╢реНрдп рд╕реНрдерд┐рддрд┐ рдХреЛ рдЕрдкрдбреЗрдЯ рдХрд░рддрд╛ рд╣реИ рдФрд░ рдирдП рдЖрдЗрдЯрдо рдХреЗ рд╕рд╛рде рд╕рдВрдЧреНрд░рд╣ рджреГрд╢реНрдп рдХреЛ рдлрд┐рд░ рд╕реЗ рд▓реЛрдб рдХрд░рддрд╛ рд╣реИред
рдЖрдкрдХреЛ рдиреАрдЪреЗ рдЙрдкрдпреЛрдЧ рдХреЗ рдФрд░ рдЕрдзрд┐рдХ рдЙрджрд╛рд╣рд░рдг рджрд┐рдЦрд╛рдИ рджреЗрдВрдЧреЗред
рддрдХрдиреАрдХ
рдЗрд╕ рдЦрдВрдб рдореЗрдВ рдореИрдВ рдЪрд╛рд░ рдпреВрдЖрдИ рд╡рд┐рдХрд╛рд╕ рддрдХрдиреАрдХреЛрдВ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдмрд╛рдд рдХрд░реВрдВрдЧрд╛ рдЬреЛ рдХрд┐ рдмрдЯреА рдореЗрдВ рдЙрдкрдпреЛрдЧ рдХреА рдЬрд╛рддреА рд╣реИрдВ
1. рдХреЛрдб рдореЗрдВ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдЗрдВрдЯрд░рдлрд╝реЗрд╕ рдХрд╛ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрдиред
2. рд▓реЗрдЖрдЙрдЯ рдПрдВрдХрд░ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдирд╛ред
3. рдШрдЯрдХ - рд╡рд┐рднрд╛рдЬрд┐рдд рдФрд░ рдЬреАрддрдирд╛ред
4. рдпреВрдЬрд░ рдЗрдВрдЯрд░рдлреЗрд╕ рдФрд░ рд▓реЙрдЬрд┐рдХ рдХрд╛ рдЕрд▓рдЧ рд╣реЛрдирд╛ред
# 1: рдХреЛрдб рдореЗрдВ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдЗрдВрдЯрд░рдлрд╝реЗрд╕ рдХреЛ рд▓рд╛рдЧреВ рдХрд░рдирд╛
Badoo рдореЗрдВ, рдЕрдзрд┐рдХрд╛рдВрд╢ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рд╣рд┐рдд рдХреЛрдб рдореЗрдВ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рд┐рдд рдХрд┐рдП рдЬрд╛рддреЗ рд╣реИрдВред рд╣рдо XIB рдпрд╛ рд╕реНрдЯреЛрд░реАрдмреЛрд░реНрдб рдХрд╛ рдЙрдкрдпреЛрдЧ рдХреНрдпреЛрдВ рдирд╣реАрдВ рдХрд░рддреЗ рд╣реИрдВ? рдирд┐рд╖реНрдкрдХреНрд╖ рдкреНрд░рд╢реНрдиред рдореБрдЦреНрдп рдХрд╛рд░рдг рдордзреНрдпрдо рдЖрдХрд╛рд░ рдХреА рдЯреАрдо рдХреЗ рд▓рд┐рдП рдХреЛрдб рдмрдирд╛рдП рд░рдЦрдиреЗ рдХреА рд╕реБрд╡рд┐рдзрд╛ рд╣реИ, рдЕрд░реНрдерд╛рддреН:
- рдХреЛрдб рдореЗрдВ рдкрд░рд┐рд╡рд░реНрддрди рд╕реНрдкрд╖реНрдЯ рд░реВрдк рд╕реЗ рджрд┐рдЦрд╛рдИ рджреЗрддреЗ рд╣реИрдВ, рдЬрд┐рд╕рдХрд╛ рдЕрд░реНрде рд╣реИ рдХрд┐ рдХрд┐рд╕реА рд╕рд╣рдпреЛрдЧреА рджреНрд╡рд╛рд░рд╛ рдХрд┐рдП рдЧрдП рдкрд░рд┐рд╡рд░реНрддрдиреЛрдВ рдХреЛ рдЦреЛрдЬрдиреЗ рдХреЗ рд▓рд┐рдП XML рд╕реНрдЯреЛрд░реАрдмреЛрд░реНрдб / XIB рдлрд╝рд╛рдЗрд▓ рдХреЛ рдкрд╛рд░реНрд╕ рдХрд░рдиреЗ рдХреА рдХреЛрдИ рдЖрд╡рд╢реНрдпрдХрддрд╛ рдирд╣реАрдВ рд╣реИ;
- рд╕рдВрд╕реНрдХрд░рдг рдирд┐рдпрдВрддреНрд░рдг рдкреНрд░рдгрд╛рд▓реА (рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рдЧрд┐рдЯ) "рднрд╛рд░реА" XLM- рдлрд╛рдЗрд▓реЛрдВ рдХреА рддреБрд▓рдирд╛ рдореЗрдВ рдХреЛрдб рдХреЗ рд╕рд╛рде рдХрд╛рдо рдХрд░рдирд╛ рдмрд╣реБрдд рдЖрд╕рд╛рди рд╣реИ, рдЦрд╛рд╕рдХрд░ рдордзреНрдпрдо рд╕рдВрдШрд░реНрд╖ рдХреЗ рджреМрд░рд╛рди; рдпрд╣ рднреА рдзреНрдпрд╛рди рдореЗрдВ рд░рдЦрд╛ рдЬрд╛рддрд╛ рд╣реИ рдХрд┐ XIB / рд╕реНрдЯреЛрд░реАрдмреЛрд░реНрдб рдлрд╝рд╛рдЗрд▓реЛрдВ рдХреА рд╕рд╛рдордЧреНрд░реА рд╣рд░ рдмрд╛рд░ рд╕рд╣реЗрдЬреЗ рдЬрд╛рдиреЗ рдХреЗ рдмрд╛рдж рднреА рдмрджрд▓ рдЬрд╛рддреА рд╣реИ, рднрд▓реЗ рд╣реА рдЗрдВрдЯрд░рдлрд╝реЗрд╕ рдирд╣реАрдВ рдмрджрд▓рд╛ рд╣реЛ (рд╣рд╛рд▓рд╛рдБрдХрд┐ рдореИрдВрдиреЗ рд╕реБрдирд╛ рд╣реИ рдХрд┐ Xcode 9 рдореЗрдВ рдпрд╣ рд╕рдорд╕реНрдпрд╛ рдкрд╣рд▓реЗ рд╕реЗ рд╣реА рддрдп рд╣реЛ рдЧрдИ рд╣реИ);
- рдЗрдВрдЯрд░рдлрд╝реЗрд╕ рдмрд┐рд▓реНрдбрд░ (рдЖрдИрдмреА) рдореЗрдВ рдХреБрдЫ рдЧреБрдгреЛрдВ рдХреЛ рдмрджрд▓рдирд╛ рдФрд░ рдмрдирд╛рдП рд░рдЦрдирд╛ рдореБрд╢реНрдХрд┐рд▓ рд╣реЛ рд╕рдХрддрд╛ рд╣реИ, рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рдмрдЪреНрдЪреЗ рдХреЗ рд╡рд┐рдЪрд╛рд░реЛрдВ (рд▓реЗрдЖрдЙрдЯ рдЙрдк рд╕рд╛рдХреНрд╖рд╛рддреНрдХрд╛рд░) рдХреА рд░рд┐рд▓реЗрдЖрдЙрдЯ рдкреНрд░рдХреНрд░рд┐рдпрд╛ рдХреЗ рджреМрд░рд╛рди рдХрд╛рдпрд░ рдЧреБрдг, рдЬреЛ рджреГрд╢реНрдп рд╕реНрдерд┐рддрд┐ рдХреЗ рд▓рд┐рдП рд╕рдЪреНрдЪрд╛рдИ рдХреЗ рдХрдИ рд╕реНрд░реЛрддреЛрдВ рдХреЛ рдЬрдиреНрдо рджреЗ рд╕рдХрддрд╛ рд╣реИ;
- рдЗрдВрдЯрд░рдлрд╝реЗрд╕ рдмрд┐рд▓реНрдбрд░ рд╕рдмрд╕реЗ рддреЗрдЬрд╝ рдЙрдкрдХрд░рдг рдирд╣реАрдВ рд╣реИ, рдФрд░ рдХрднреА-рдХрднреА рдХреЛрдб рдХреЗ рд╕рд╛рде рд╕реАрдзреЗ рдХрд╛рдо рдХрд░рдирд╛ рдмрд╣реБрдд рддреЗрдЬрд╝ рд╣реЛрддрд╛ рд╣реИред
рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рдирд┐рдпрдВрддреНрд░рдХ (FriendsListViewController) рдкрд░ рдПрдХ рдирдЬрд╝рд░ рдбрд╛рд▓реЗрдВ:
final class FriendsListViewController: UIViewController { struct ViewConfig { let backgroundColor: UIColor let cornerRadius: CGFloat } private var infoView: FriendsListView! private let viewModel: FriendsListViewModelProtocol private let viewConfig: ViewConfig init(viewModel: FriendsListViewModelProtocol, viewConfig: ViewConfig) { self.viewModel = viewModel self.viewConfig = viewConfig super.init(nibName: nil, bundle: nil) } required init?(coder aDecoder: NSCoder) { fatalError("init(coder:) has not been implemented") } override func viewDidLoad() { super.viewDidLoad() self.setupContainerView() } private func setupContainerView() { self.view.backgroundColor = self.viewConfig.backgroundColor let infoView = FriendsListView( frame: .zero, viewModel: self.viewModel, viewConfig: .defaultConfig) infoView.backgroundColor = self.viewConfig.backgroundColor self.view.addSubview(infoView) self.infoView = infoView infoView.translatesAutoresizingMaskIntoConstraints = false infoView.leadingAnchor.constraint(equalTo: self.view.leadingAnchor).isActive = true infoView.trailingAnchor.constraint(equalTo: self.view.trailingAnchor).isActive = true infoView.topAnchor.constraint(equalTo: self.view.topAnchor).isActive = true infoView.bottomAnchor.constraint(equalTo: self.view.bottomAnchor).isActive = true }
рдпрд╣ рдЙрджрд╛рд╣рд░рдг рджрд┐рдЦрд╛рддрд╛ рд╣реИ рдХрд┐ рдЖрдк рдХреЗрд╡рд▓ рджреГрд╢реНрдп рдореЙрдбрд▓ рдФрд░ рджреГрд╢реНрдп рдХреЙрдиреНрдлрд╝рд┐рдЧрд░реЗрд╢рди рдкреНрд░рджрд╛рди рдХрд░рдХреЗ рдПрдХ рджреГрд╢реНрдп рдирд┐рдпрдВрддреНрд░рдХ рдмрдирд╛ рд╕рдХрддреЗ рд╣реИрдВред рдЖрдк рдкреНрд░рд╕реНрддреБрддрд┐ рдореЙрдбрд▓ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдЕрдзрд┐рдХ рдкрдврд╝ рд╕рдХрддреЗ рд╣реИрдВ, рдЕрд░реНрдерд╛рддреН, рдПрдорд╡реАрд╡реАрдПрдо рдбрд┐рдЬрд╝рд╛рдЗрди рдореЙрдбрд▓ (рдореЙрдбрд▓-рд╡реНрдпреВ-рд╡реНрдпреВрдореЙрдбрд▓)
рдпрд╣рд╛рдБ ред рдЪреВрдБрдХрд┐ рджреГрд╢реНрдп рд╡рд┐рдиреНрдпрд╛рд╕ рдПрдХ рд╕рд╛рдзрд╛рд░рдг рд╕рдВрд░рдЪрдирд╛рддреНрдордХ рдЗрдХрд╛рдИ (рд╕рдВрд░рдЪрдирд╛ рдЗрдХрд╛рдИ) рд╣реИ рдЬреЛ рджреГрд╢реНрдп, рд▓реЗрдЖрдЙрдЯ рдФрд░ рд╢реИрд▓реА, рдЬреИрд╕реЗ рдЗрдВрдбреЗрдВрдЯ, рдЖрдХрд╛рд░, рд░рдВрдЧ, рдлрд╝реЙрдиреНрдЯ рдЖрджрд┐ рдХреЛ рдкрд░рд┐рднрд╛рд╖рд┐рдд рдХрд░рддрд╛ рд╣реИ, рдореИрдВ рдЗрд╕ рддрд░рд╣ рдПрдХ рдорд╛рдирдХ рд╡рд┐рдиреНрдпрд╛рд╕ рдкреНрд░рджрд╛рди рдХрд░рдирд╛ рдЙрдЪрд┐рдд рд╕рдордЭрддрд╛ рд╣реВрдВ:
extension FriendsListViewController.ViewConfig { static var defaultConfig: FriendsListViewController.ViewConfig { return FriendsListViewController.ViewConfig(backgroundColor: .white, cornerRadius: 16) } }
рд╕рднреА рджреГрд╢реНрдп рдЖрд░рдВрднреАрдХрд░рдг
setupContainerView
рд╡рд┐рдзрд┐ рдореЗрдВ рд╣реЛрддрд╛ рд╣реИ, рдЬрд┐рд╕реЗ
setupContainerView
рд╕реЗ рдХреЗрд╡рд▓ рдПрдХ рдмрд╛рд░ рдХрд╣рд╛ рдЬрд╛рддрд╛ рд╣реИ рдЬрдм рджреГрд╢реНрдп рдкрд╣рд▓реЗ рд╕реЗ рд╣реА рдмрдирд╛рдпрд╛ рдФрд░ рд▓реЛрдб рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ, рд▓реЗрдХрд┐рди рдЕрднреА рддрдХ рд╕реНрдХреНрд░реАрди рдкрд░ рдирд╣реАрдВ рдЦреАрдВрдЪрд╛ рдЬрд╛рддрд╛ рд╣реИ, рдЕрд░реНрдерд╛рдд, рд╕рднреА рдЖрд╡рд╢реНрдпрдХ рддрддреНрд╡ (рд╕рд╛рдХреНрд╖рд╛рддреНрдХрд╛рд░) рдХреЗрд╡рд▓ рджреГрд╢реНрдп рдкрджрд╛рдиреБрдХреНрд░рдо рдореЗрдВ рдЬреЛрдбрд╝реЗ рдЬрд╛рддреЗ рд╣реИрдВ, рдФрд░ рдлрд┐рд░ рдорд╛рд░реНрдХрдЕрдк рд▓рд╛рдЧреВ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ (рд▓реЗрдЖрдЙрдЯ) рдФрд░ рд╢реИрд▓рд┐рдпреЛрдВред
рдЕрдм рджреЗрдЦрдиреЗ рд╡рд╛рд▓рд╛ рдХрдВрдЯреНрд░реЛрд▓рд░ рдХреИрд╕рд╛ рджрд┐рдЦрддрд╛ рд╣реИ:
final class FriendsListPresenter: FriendsListPresenterProtocol { // тАж func presentFriendsList(from presentingViewController: UIViewController) { let controller = Class.createFriendsListViewController( presentingViewController: presentingViewController, headerViewModel: self.headerViewModel, contentViewModel: self.contentViewModel) controller.modalPresentationStyle = .overCurrentContext controller.modalTransitionStyle = .crossDissolve presentingViewController.present(controller, animated: true, completion: nil) } private class func createFriendsListViewController( presentingViewController: UIViewController, headerViewModel: FriendsListHeaderViewModelProtocol, contentViewModel: FriendsListContentViewModelProtocol) -> FriendsListContainerViewController { let dismissViewControllerBlock: VoidBlock = { [weak presentingViewController] in presentingViewController?.dismiss(animated: true, completion: nil) } let infoViewModel = FriendsListViewModel( headerViewModel: headerViewModel, contentViewModel: contentViewModel) let containerViewModel = FriendsListContainerViewModel(onOutsideContentTapAction: dismissViewControllerBlock) let friendsListViewController = FriendsListViewController( viewModel: infoViewModel, viewConfig: .defaultConfig) let controller = FriendsListContainerViewController( contentViewController: friendsListViewController, viewModel: containerViewModel, viewConfig: .defaultConfig) return controller } }
рдЖрдк
рдЬрд┐рдореНрдореЗрджрд╛рд░рд┐рдпреЛрдВ рдХрд╛ рд╕реНрдкрд╖реНрдЯ
рдкреГрдердХреНрдХрд░рдг рджреЗрдЦ рд╕рдХрддреЗ рд╣реИрдВ, рдФрд░ рдпрд╣ рдЕрд╡рдзрд╛рд░рдгрд╛ рд╕реНрдЯреЛрд░реАрдмреЛрд░реНрдб рдкрд░ рд╕реЗрдЧрд┐рдВрдЧ рдХреА рддреБрд▓рдирд╛ рдореЗрдВ рдмрд╣реБрдд рдЕрдзрд┐рдХ рдЬрдЯрд┐рд▓ рдирд╣реАрдВ рд╣реИред
рдПрдХ рджреГрд╢реНрдп рдирд┐рдпрдВрддреНрд░рдХ рдмрдирд╛рдирд╛ рдХрд╛рдлреА рд╕рд░рд▓ рд╣реИ, рдпрд╣ рджреЗрдЦрддреЗ рд╣реБрдП рдХрд┐ рд╣рдорд╛рд░реЗ рдкрд╛рд╕ рдЗрд╕рдХрд╛ рдореЙрдбрд▓ рд╣реИ рдФрд░ рдЖрдк рдмрд╕ рдорд╛рдирдХ рджреГрд╢реНрдп рд╡рд┐рдиреНрдпрд╛рд╕ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ:
let friendsListViewController = FriendsListViewController( viewModel: infoViewModel, viewConfig: .defaultConfig)
# 2: рд▓реЗрдЖрдЙрдЯ рдПрдВрдХрд░ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдирд╛
рдпрд╣рд╛рдБ рд▓реЗрдЖрдЙрдЯ рдХреЛрдб рд╣реИ:
self.view.addSubview(infoView) self.infoView = infoView infoView.translatesAutoresizingMaskIntoConstraints = false infoView.leadingAnchor.constraint(equalTo: self.view.leadingAnchor).isActive = true infoView.trailingAnchor.constraint(equalTo: self.view.trailingAnchor).isActive = true infoView.topAnchor.constraint(equalTo: self.view.topAnchor).isActive = true infoView.bottomAnchor.constraint(equalTo: self.view.bottomAnchor).isActive = true
рд╕реАрдзреЗ рд╢рдмреНрджреЛрдВ рдореЗрдВ рдХрд╣реЗрдВ, рддреЛ рдпрд╣ рдХреЛрдб рдореВрд▓ рджреГрд╢реНрдп (
infoView
рдЕрдВрджрд░
infoView
, рдирд┐рд░реНрджреЗрд╢рд╛рдВрдХ рдХреЗ рдореВрд▓ рдЖрдХрд╛рд░ рдХреЗ рд╕рд╛рдкреЗрдХреНрд╖ рдирд┐рд░реНрджреЗрд╢рд╛рдВрдХ (0, 0) рдХреЗ рдЕрдВрджрд░ рд░рдЦрддрд╛ рд╣реИред
рд╣рдо рд▓реЗрдЖрдЙрдЯ рдПрдВрдХрд░ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХреНрдпреЛрдВ рдХрд░рддреЗ рд╣реИрдВ? рдпрд╣ рддреНрд╡рд░рд┐рдд рдФрд░ рдЖрд╕рд╛рди рд╣реИред рдмреЗрд╢рдХ, рдЖрдк рдореИрдиреНрдпреБрдЕрд▓ рд░реВрдк рд╕реЗ UIView.frame рд╕реЗрдЯ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ рдФрд░ рдордХреНрдЦреА рдкрд░ рд╕рднреА рдкрджреЛрдВ рдФрд░ рдЖрдХрд╛рд░реЛрдВ рдХреА рдЧрдгрдирд╛ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ, рд▓реЗрдХрд┐рди рдХрднреА-рдХрднреА рдпрд╣ рдмрд╣реБрдд рднреНрд░рд╛рдордХ рдФрд░ / рдпрд╛ рднрд╛рд░реА рдХреЛрдб рд╣реЛ рд╕рдХрддрд╛ рд╣реИред
рдЖрдк рдорд╛рд░реНрдХрдЕрдк рдХреЗ рд▓рд┐рдП рдПрдХ рдкрд╛рда рдкреНрд░рд╛рд░реВрдк рдХрд╛ рдЙрдкрдпреЛрдЧ рднреА рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ, рдЬреИрд╕рд╛ рдХрд┐
рдпрд╣рд╛рдВ рд╡рд░реНрдгрд┐рдд
рд╣реИ , рд▓реЗрдХрд┐рди рдЕрдХреНрд╕рд░ рдпрд╣ рддреНрд░реБрдЯрд┐рдпреЛрдВ рдХреА рдУрд░ рдЬрд╛рддрд╛ рд╣реИ, рдХреНрдпреЛрдВрдХрд┐ рдЖрдкрдХреЛ рдкреНрд░рд╛рд░реВрдк рдХрд╛ рдХрдбрд╝рд╛рдИ рд╕реЗ рдкрд╛рд▓рди рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ, рдФрд░ рдХреЛрдб рд▓рд┐рдЦрдиреЗ / рд╕рдВрдХрд▓рд┐рдд рдХрд░рдиреЗ рдХреЗ рдЪрд░рдг рдореЗрдВ Xcode рдорд╛рд░реНрдХрдЕрдк рд╡рд┐рд╡рд░рдг рдкрд╛рда рдХреА рдЬрд╛рдВрдЪ рдирд╣реАрдВ рдХрд░рддрд╛ рд╣реИ, рдФрд░ рдЖрдк рд╕реБрд░рдХреНрд╖рд┐рдд рдХреНрд╖реЗрддреНрд░ рд▓реЗрдЖрдЙрдЯ рдЧрд╛рдЗрдб рдХрд╛ рдЙрдкрдпреЛрдЧ рдирд╣реАрдВ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ:
NSLayoutConstraint.constraints( withVisualFormat: "V:|-(\(topSpace))-[headerView(headerHeight@200)]-[collectionView(collectionViewHeight@990)]|", options: [], metrics: metrics, views: views)
рдорд╛рд░реНрдХрдЕрдк рдХреЛ рд╕рд╣реА рдХрд░рдиреЗ рд╡рд╛рд▓реЗ рдЯреЗрдХреНрд╕реНрдЯ рд╕реНрдЯреНрд░рд┐рдВрдЧ рдореЗрдВ рдЧрд▓рддреА рдпрд╛ рдЯрд╛рдЗрдкреЛ рдмрдирд╛рдирд╛ рдмрд╣реБрдд рдЖрд╕рд╛рди рд╣реИ?
# 3: рдШрдЯрдХ - рдлреВрдЯ рдбрд╛рд▓реЛ рдФрд░ рдЬреАрддреЛ
рд╣рдорд╛рд░рд╛ рдЙрджрд╛рд╣рд░рдг рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдЗрдВрдЯрд░рдлрд╝реЗрд╕ рдШрдЯрдХреЛрдВ рдореЗрдВ рд╡рд┐рднрд╛рдЬрд┐рдд рд╣реИ, рдЬрд┐рдирдореЗрдВ рд╕реЗ рдкреНрд░рддреНрдпреЗрдХ рдПрдХ рд╡рд┐рд╢рд┐рд╖реНрдЯ рдХрд╛рд░реНрдп рдХрд░рддрд╛ рд╣реИ, рдФрд░ рдирд╣реАрдВред
рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП:
FriendsListHeaderView
- рджреЛрд╕реНрддреЛрдВ рдФрд░ рдмрдВрдж рдмрдЯрди рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдЬрд╛рдирдХрд╛рд░реА рдкреНрд░рджрд░реНрд╢рд┐рдд рдХрд░рддрд╛ рд╣реИредFriendsListContentView
- рдХреНрд▓рд┐рдХ рдХрд░рдиреЗ рдпреЛрдЧреНрдп рдХреЛрд╢рд┐рдХрд╛рдУрдВ рдХреЗ рд╕рд╛рде рджреЛрд╕реНрддреЛрдВ рдХреА рдПрдХ рд╕реВрдЪреА рдкреНрд░рджрд░реНрд╢рд┐рдд рдХрд░рддрд╛ рд╣реИ, рд╕реВрдЪреА рдХреЗ рдЕрдВрдд рддрдХ рдкрд╣реБрдВрдЪрдиреЗ рдкрд░ рд╕рд╛рдордЧреНрд░реА рдЧрддрд┐рд╢реАрд▓ рд░реВрдк рд╕реЗ рднрд░реА рд╣реБрдИ рд╣реИредFriendsListView
- рджреЛ рдкрд┐рдЫрд▓реЗ рд╡рд┐рдЪрд╛рд░реЛрдВ рдХреЗ рд▓рд┐рдП рдПрдХ рдХрдВрдЯреЗрдирд░ред
рдЬреИрд╕рд╛ рдХрд┐ рдкрд╣рд▓реЗ рдЙрд▓реНрд▓реЗрдЦ рдХрд┐рдпрд╛ рдЧрдпрд╛ рд╣реИ, рд╣рдо рдкреНрд░рддреНрдпреЗрдХ рдШрдЯрдХ рдХреЗ рдЕрд▓рдЧ-рдЕрд▓рдЧ рдХрд╛рд░реНрдп рдХреЗ рд▓рд┐рдП
рдЬрд┐рдореНрдореЗрджрд╛рд░ рд╣реЛрдиреЗ рдкрд░
, рдПрдХрдорд╛рддреНрд░ рдЬрд┐рдореНрдореЗрджрд╛рд░реА рдХреЗ
рд╕рд┐рджреНрдзрд╛рдВрдд рдХреЛ рдкрд╕рдВрдж рдХрд░рддреЗ рд╣реИрдВред рдпрд╣ рди рдХреЗрд╡рд▓ рдмрдЧ рдлрд┐рдХреНрд╕рд┐рдВрдЧ рдХреА рдкреНрд░рдХреНрд░рд┐рдпрд╛ рдореЗрдВ рдорджрдж рдХрд░рддрд╛ рд╣реИ (рдЬреЛ, рд╢рд╛рдпрдж, рдЖрдИрдУрдПрд╕ рдбреЗрд╡рд▓рдкрд░ рдХреЗ рдХрд╛рдо рдХрд╛ рд╕рдмрд╕реЗ рджрд┐рд▓рдЪрд╕реНрдк рд╣рд┐рд╕реНрд╕рд╛ рдирд╣реАрдВ рд╣реИ), рдмрд▓реНрдХрд┐ рдирдИ рдХрд╛рд░реНрдпрдХреНрд╖рдорддрд╛ рдХреЗ рд╡рд┐рдХрд╛рд╕ рдХреЗ рджреМрд░рд╛рди рднреА, рдХреНрдпреЛрдВрдХрд┐ рдпрд╣ рджреГрд╖реНрдЯрд┐рдХреЛрдг рднрд╡рд┐рд╖реНрдп рдореЗрдВ рдХреЛрдб рдХреЗ рдкреБрди: рдЙрдкрдпреЛрдЧ рдХреА рд╕рдВрднрд╛рд╡рдирд╛рдУрдВ рдХреЛ рдХрд╛рдлреА рдмрдврд╝рд╛рддрд╛ рд╣реИред
# 4: рдпреВрдЬрд░ рдЗрдВрдЯрд░рдлреЗрд╕ рдФрд░ рд▓реЙрдЬрд┐рдХ рдХреЛ рдЕрд▓рдЧ рдХрд░рдирд╛
рдФрд░ рдЕрдВрддрд┐рдо, рд▓реЗрдХрд┐рди рдХреЛрдИ рдХрдо рдорд╣рддреНрд╡рдкреВрд░реНрдг рдмрд┐рдВрджреБ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдЗрдВрдЯрд░рдлрд╝реЗрд╕ рдФрд░ рддрд░реНрдХ рдХрд╛ рдЕрд▓рдЧрд╛рд╡ рдирд╣реАрдВ рд╣реИред рдПрдХ рдРрд╕реА рддрдХрдиреАрдХ рдЬреЛ рдЖрдкрдХреА рдЯреАрдо рдХреЗ рд▓рд┐рдП рд╕рдордп рдФрд░ рдирд╕реЛрдВ рдХреЛ рдмрдЪрд╛ рд╕рдХрддреА рд╣реИред рд╢рд╛рдмреНрджрд┐рдХ рдЕрд░реНрде рдореЗрдВ: рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдЗрдВрдЯрд░рдлрд╝реЗрд╕ рдХреЗ рд▓рд┐рдП рдПрдХ рдЕрд▓рдЧ рдкрд░рд┐рдпреЛрдЬрдирд╛ рдФрд░ рд╡реНрдпрд╛рд╡рд╕рд╛рдпрд┐рдХ рддрд░реНрдХ рдХреЗ рд▓рд┐рдП рдПрдХ рдЕрд▓рдЧред
рдЖрдЗрдП рд╣рдо рдЕрдкрдиреЗ рдЙрджрд╛рд╣рд░рдг рдкрд░ рд▓реМрдЯрддреЗ рд╣реИрдВред рдЬреИрд╕рд╛ рдХрд┐ рдЖрдк рдпрд╛рдж рдХрд░рддреЗ рд╣реИрдВ, рдкреНрд░рд╕реНрддреБрддрд┐ рдХрд╛ рд╕рд╛рд░ (рдкреНрд░рд╕реНрддреБрддрдХрд░реНрддрд╛) рдЗрд╕ рддрд░рд╣ рджрд┐рдЦрддрд╛ рд╣реИ:
func presentFriendsList(from presentingViewController: UIViewController) { let controller = Class.createFriendsListViewController( presentingViewController: presentingViewController, headerViewModel: self.headerViewModel, contentViewModel: self.contentViewModel) controller.modalPresentationStyle = .overCurrentContext controller.modalTransitionStyle = .crossDissolve presentingViewController.present(controller, animated: true, completion: nil) }
рдЖрдкрдХреЛ рдХреЗрд╡рд▓ рд╢реАрд░реНрд╖рдХ рдФрд░ рд╕рд╛рдордЧреНрд░реА рдХреЗ рд▓рд┐рдП рджреГрд╢реНрдп рдореЙрдбрд▓ рдкреНрд░рджрд╛рди рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИред рдмрд╛рдХреА рдпреВрдЖрдИ рдШрдЯрдХреЛрдВ рдХреЗ рдЙрдкрд░реЛрдХреНрдд рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рдХреЗ рдЕрдВрджрд░ рдЫрд┐рдкрд╛ рд╣реБрдЖ рд╣реИред
рд╢реАрд░реНрд╖ рд▓реЗрдЦ рджреГрд╢реНрдп рдореЙрдбрд▓ рдкреНрд░реЛрдЯреЛрдХреЙрд▓ рдЗрд╕ рддрд░рд╣ рджрд┐рдЦрддрд╛ рд╣реИ:
protocol FriendsListHeaderViewModelProtocol { var friendsCountIcon: UIImage? { get } var closeButtonIcon: UIImage? { get } var friendsCount: Observable<String> { get } var onCloseAction: VoidBlock? { get set } }
рдЕрдм рдХрд▓реНрдкрдирд╛ рдХрд░реЗрдВ рдХрд┐ рдЖрдк UI рдХреЗ рд▓рд┐рдП рджреГрд╢реНрдп рдкрд░реАрдХреНрд╖рдг рдЬреЛрдбрд╝ рд░рд╣реЗ рд╣реИрдВ - рдпрд╣ рдпреВрдЖрдИ рдШрдЯрдХреЛрдВ рдХреЗ рд▓рд┐рдП рд╕реНрдЯрдм рдореЙрдбрд▓ рдкрд╛рд╕ рдХрд░рдиреЗ рдХреЗ рд╕рдорд╛рди рд╕рд░рд▓ рд╣реИред
final class FriendsListHeaderDemoViewModel: FriendsListHeaderViewModelProtocol { var friendsCountIcon: UIImage? = UIImage(named: "ic_friends_count") var closeButtonIcon: UIImage? = UIImage(named: "ic_close_cross") var friendsCount: Observable<String> var onCloseAction: VoidBlock? init() { let friendsCountString = "\(Int.random(min: 1, max: 5000))" self.friendsCount = Observable(friendsCountString) } }
рдпрд╣ рд╕рд░рд▓ рд▓рдЧрддрд╛ рд╣реИ, рд╣реИ рдирд╛? рдЕрдм рд╣рдо рдЕрдкрдиреЗ рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдХреЗ рдШрдЯрдХреЛрдВ рдореЗрдВ рд╡реНрдпрд╛рд╡рд╕рд╛рдпрд┐рдХ рддрд░реНрдХ рдЬреЛрдбрд╝рдирд╛ рдЪрд╛рд╣рддреЗ рд╣реИрдВ, рдЬрд┐рд╕рдХреЗ рд▓рд┐рдП рдбреЗрдЯрд╛ рдкреНрд░рджрд╛рддрд╛, рдбреЗрдЯрд╛ рдореЙрдбрд▓ рдЖрджрд┐ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реЛ рд╕рдХрддреА рд╣реИред
final class FriendsListHeaderViewModel: FriendsListHeaderViewModelProtocol { let friendsCountIcon: UIImage? let closeButtonIcon: UIImage? let friendsCount: Observable<String> = Observable("0") var onCloseAction: VoidBlock? private let dataProvider: FriendsListDataProviderProtocol private var observers: [ObserverProtocol] = [] init(dataProvider: FriendsListDataProviderProtocol, friendsCountIcon: UIImage?, closeButtonIcon: UIImage?) { self.dataProvider = dataProvider self.friendsCountIcon = friendsCountIcon self.closeButtonIcon = closeButtonIcon self.setupDataObservers() } private func setupDataObservers() { self.observers.append(self.dataProvider.totalItemsCount.observeNewAndCall { [weak self] (newCount) in self?.friendsCount.value = "\(newCount)" }) } }
рдХреНрдпрд╛ рдЖрд╕рд╛рди рд╣реЛ рд╕рдХрддрд╛ рд╣реИ? рдмрд╕ рдбреЗрдЯрд╛ рдкреНрд░рджрд╛рддрд╛ рдХреЛ рд▓рд╛рдЧреВ рдХрд░реЗрдВ - рдФрд░ рдЬрд╛рдУ!
рд╕рд╛рдордЧреНрд░реА рдореЙрдбрд▓ рдХрд╛ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рдереЛрдбрд╝рд╛ рдЕрдзрд┐рдХ рдЬрдЯрд┐рд▓ рджрд┐рдЦрддрд╛ рд╣реИ, рд▓реЗрдХрд┐рди рдЬрд┐рдореНрдореЗрджрд╛рд░рд┐рдпреЛрдВ рдХрд╛ рдЕрд▓рдЧ рд╣реЛрдирд╛ рдЕрднреА рднреА рдЬреАрд╡рди рдХреЛ рд╕рд░рд▓ рдмрдирд╛рддрд╛ рд╣реИред рдПрдХ рдмрдЯрди рдХреЗ рдХреНрд▓рд┐рдХ рдкрд░ рдорд┐рддреНрд░реЛрдВ рдХреА рд╕реВрдЪреА рдХреЛ рддреБрд░рдВрдд рдХреИрд╕реЗ рдкреНрд░рджрд░реНрд╢рд┐рдд рдФрд░ рдкреНрд░рджрд░реНрд╢рд┐рдд рдХрд┐рдпрд╛ рдЬрд╛рдП, рдЗрд╕рдХрд╛ рдПрдХ рдЙрджрд╛рд╣рд░рдг рдЗрд╕ рдкреНрд░рдХрд╛рд░ рд╣реИ:
private func presentRealFriendsList(sender: Any) { let avatarPlaceholderImage = UIImage(named: "avatar-placeholder") let itemFactory = FriendsListItemFactory(avatarPlaceholderImage: avatarPlaceholderImage) let dataProvider = FriendsListDataProvider(itemFactory: itemFactory) let viewModelFactory = FriendsListViewModelFactory(dataProvider: dataProvider) var headerViewModel = viewModelFactory.makeHeaderViewModel() headerViewModel.onCloseAction = { [weak self] in self?.dismiss(animated: true, completion: nil) } let contentViewModel = viewModelFactory.makeContentViewModel() let presenter = FriendsListPresenter( headerViewModel: headerViewModel, contentViewModel: contentViewModel) presenter.presentFriendsList(from: self) }
рдпрд╣ рддрдХрдиреАрдХ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдЗрдВрдЯрд░рдлрд╝реЗрд╕ рдХреЛ рд╡реНрдпрд╛рд╡рд╕рд╛рдпрд┐рдХ рддрд░реНрдХ рд╕реЗ рдЕрд▓рдЧ рдХрд░рдиреЗ рдореЗрдВ рдорджрдж рдХрд░рддреА рд╣реИред рдЗрд╕рдХреЗ рдЕрд▓рд╛рд╡рд╛, рдпрд╣ рдЖрдкрдХреЛ рд╕рдВрдкреВрд░реНрдг рдпреВрдЖрдИ рдХреЛ рджреГрд╢реНрдп рдкрд░реАрдХреНрд╖рдгреЛрдВ рдХреЗ рд╕рд╛рде рдХрд╡рд░ рдХрд░рдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рджреЗрддрд╛ рд╣реИ, рдШрдЯрдХреЛрдВ рдХреЛ рдкрд░реАрдХреНрд╖рдг рдбреЗрдЯрд╛ рдкрд╛рд╕ рдХрд░ рд░рд╣рд╛ рд╣реИ! рдЗрд╕рд▓рд┐рдП, рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдЗрдВрдЯрд░рдлрд╝реЗрд╕ рдФрд░ рд╕рдВрдмрдВрдзрд┐рдд рд╡реНрдпрд╛рд╡рд╕рд╛рдпрд┐рдХ рддрд░реНрдХ рдХрд╛ рдкреГрдердХреНрдХрд░рдг рдкрд░рд┐рдпреЛрдЬрдирд╛ рдХреА рд╕рдлрд▓рддрд╛ рдХреЗ рд▓рд┐рдП рдорд╣рддреНрд╡рдкреВрд░реНрдг рд╣реИ, рдЪрд╛рд╣реЗ рд╡рд╣ рдПрдХ рд╕реНрдЯрд╛рд░реНрдЯрдЕрдк рд╣реЛ рдпрд╛ рдкрд╣рд▓реЗ рд╕реЗ рддреИрдпрд╛рд░ рдЙрддреНрдкрд╛рджред
рдирд┐рд╖реНрдХрд░реНрд╖
рдмреЗрд╢рдХ, рдпреЗ рдмрд╕ рдХреБрдЫ рддрдХрдиреАрдХреЛрдВ рдХрд╛ рдЗрд╕реНрддреЗрдорд╛рд▓ рдХрд┐рдпрд╛ рдЧрдпрд╛ рд╣реИ, рдФрд░ рд╡реЗ рд╕рднреА рд╕рдВрднрд╛рд╡рд┐рдд рдорд╛рдорд▓реЛрдВ рдХреЗ рд▓рд┐рдП рдПрдХ рд╕рд╛рд░реНрд╡рднреМрдорд┐рдХ рд╕рдорд╛рдзрд╛рди рдирд╣реАрдВ рд╣реИрдВред рдЗрд╕рд▓рд┐рдП, рдЙрдирдХрд╛ рдореВрд▓реНрдпрд╛рдВрдХрди рдХрд░рдиреЗ рдХреЗ рдмрд╛рдж рдЙрдирдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░реЗрдВ рдХрд┐ рдХреНрдпрд╛ рд╡реЗ рдЖрдкрдХреЗ рдФрд░ рдЖрдкрдХреА рдкрд░рд┐рдпреЛрдЬрдирд╛рдУрдВ рдХреЗ рд▓рд┐рдП рдЙрдкрдпреБрдХреНрдд рд╣реИрдВред
рдЕрдиреНрдп рд╡рд┐рдзрд┐рдпрд╛рдВ рд╣реИрдВ, рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рдЗрдВрдЯрд░рдлрд╝реЗрд╕ рдмрд┐рд▓реНрдбрд░ (рд╡реЗ
рд╣рдорд╛рд░реЗ рдЕрдиреНрдп
рд▓реЗрдЦ рдореЗрдВ рд╡рд░реНрдгрд┐рдд рд╣реИрдВ) рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рд╣реБрдП рдПрдХреНрд╕рдЖрдИрдмреА-рд╡рд┐рдиреНрдпрд╛рд╕ рдпреЛрдЧреНрдп рдпреВрдЖрдИ-рдШрдЯрдХ, рд▓реЗрдХрд┐рди рд╡рд┐рднрд┐рдиреНрди рдХрд╛рд░рдгреЛрдВ рд╕реЗ рдЙрдирдХрд╛ рдЙрдкрдпреЛрдЧ рдирд╣реАрдВ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред рдпрд╛рдж рд░рдЦреЗрдВ рдХрд┐ рд╕рднреА рдХреА рдЕрдкрдиреА рд░рд╛рдп рдФрд░ рдмрдбрд╝реА рддрд╕реНрд╡реАрд░ рдХреА рджреГрд╖реНрдЯрд┐ рд╣реИ, рдЗрд╕рд▓рд┐рдП, рдПрдХ рд╕рдлрд▓ рдкрд░рд┐рдпреЛрдЬрдирд╛ рдХреЛ рд╡рд┐рдХрд╕рд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рдЖрдкрдХреЛ рдЯреАрдо рдореЗрдВ рдПрдХ рдЖрдо рд╕рд╣рдорддрд┐ рдкрд░ рдЖрдирд╛ рдЪрд╛рд╣рд┐рдП рдФрд░ рдЕрдзрд┐рдХрд╛рдВрд╢ рдкрд░рд┐рджреГрд╢реНрдпреЛрдВ рдХреЗ рд▓рд┐рдП рд╕рдмрд╕реЗ рдЙрдкрдпреБрдХреНрдд рджреГрд╖реНрдЯрд┐рдХреЛрдг рдХрд╛ рдЪрдпрди рдХрд░рдирд╛ рдЪрд╛рд╣рд┐рдПред
рдЖрдкрдХреЗ рд╕рд╛рде рд╣реЛ рд╕рдХрддрд╛ рд╣реИ рд╕реНрд╡рд┐рдлреНрдЯ!
рд╕реВрддреНрд░реЛрдВ рдХрд╛ рдХрд╣рдирд╛ рд╣реИ