IOS рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдореЗрдВ рдШрдЯрдХ UI рдЖрд░реНрдХрд┐рдЯреЗрдХреНрдЪрд░



рдирдорд╕реНрдХрд╛рд░, рд╣реЗрдмреНрд░!

рдореЗрд░рд╛ рдирд╛рдо рд╡рд▓реЗрд░рд╛ рд╣реИ, рдФрд░ рдЕрдм рджреЛ рд╕рд╛рд▓ рд╕реЗ рдореИрдВ рдПрдХ iOS рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдХреЛ рд╡рд┐рдХрд╕рд┐рдд рдХрд░ рд░рд╣рд╛ рд╣реВрдВ, рдЬреЛ рдХрд┐ рдЯреАрдо рдХрд╛ рд╣рд┐рд╕реНрд╕рд╛ рд╣реИред рд╣рдорд╛рд░реА рдкреНрд░рд╛рдердорд┐рдХрддрд╛рдУрдВ рдореЗрдВ рд╕реЗ рдПрдХ рдХреЛрдб рдХреЛ рдмрдирд╛рдП рд░рдЦрдирд╛ рдЖрд╕рд╛рди рд╣реИред рд╕рд╛рдкреНрддрд╛рд╣рд┐рдХ рд░реВрдк рд╕реЗ рд╣рдорд╛рд░реЗ рд╣рд╛рдереЛрдВ рдореЗрдВ рдЖрдиреЗ рд╡рд╛рд▓реА рдирдИ рд╕реБрд╡рд┐рдзрд╛рдУрдВ рдХреА рдмрдбрд╝реА рд╕рдВрдЦреНрдпрд╛ рдХреЗ рдХрд╛рд░рдг, рд╣рдореЗрдВ рдкрд╣рд▓реЗ рдЖрд╡реЗрджрди рдХреА рд╡рд╛рд╕реНрддреБрдХрд▓рд╛ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рд╕реЛрдЪрдирд╛ рд╣реЛрдЧрд╛, рдЕрдиреНрдпрдерд╛ рдореМрдЬреВрджрд╛ рд╡рд┐рд╢реЗрд╖рддрд╛рдУрдВ рдХреЛ рддреЛрдбрд╝реЗ рдмрд┐рдирд╛ рдЙрддреНрдкрд╛рдж рдореЗрдВ рдПрдХ рдирдИ рд╕реБрд╡рд┐рдзрд╛ рдЬреЛрдбрд╝рдирд╛ рдмреЗрд╣рдж рдореБрд╢реНрдХрд┐рд▓ рд╣реЛрдЧрд╛ред рдЬрд╛рд╣рд┐рд░ рд╣реИ, рдпрд╣ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдЗрдВрдЯрд░рдлрд╝реЗрд╕ (UI) рдХреЗ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рдкрд░ рднреА рд▓рд╛рдЧреВ рд╣реЛрддрд╛ рд╣реИ, рднрд▓реЗ рд╣реА рдпрд╣ рдХреЛрдб, Xcode (XIB) рдпрд╛ рдорд┐рд╢реНрд░рд┐рдд рджреГрд╖реНрдЯрд┐рдХреЛрдг рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдХрд┐рдпрд╛ рдЧрдпрд╛ рд╣реЛред рдЗрд╕ рд▓реЗрдЦ рдореЗрдВ рдореИрдВ рдХреБрдЫ рдпреВрдЖрдИ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рддрдХрдиреАрдХреЛрдВ рдХрд╛ рд╡рд░реНрдгрди рдХрд░реВрдВрдЧрд╛ рдЬреЛ рд╣рдореЗрдВ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдЗрдВрдЯрд░рдлрд╝реЗрд╕ рдХреЗ рд╡рд┐рдХрд╛рд╕ рдХреЛ рд╕рд░рд▓ рдмрдирд╛рдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рджреЗрддреЗ рд╣реИрдВ, рдЬрд┐рд╕рд╕реЗ рдпрд╣ рдкрд░реАрдХреНрд╖рдг рдХреЗ рд▓рд┐рдП рд▓рдЪреАрд▓рд╛ рдФрд░ рд╕реБрд╡рд┐рдзрд╛рдЬрдирдХ рд╣реЛ рдЬрд╛рддрд╛ рд╣реИред рдЗрд╕ рд▓реЗрдЦ рдХрд╛ рдПрдХ рдЕрдВрдЧреНрд░реЗрдЬреА рд╕рдВрд╕реНрдХрд░рдг рднреА рд╣реИред

рд╢реБрд░реВ рдХрд░рдиреЗ рд╕реЗ рдкрд╣рд▓реЗ ...


рдореИрдВ рд╕реНрд╡рд┐рдлреНрдЯ рдореЗрдВ рд▓рд┐рдЦреЗ рдЧрдП рдПрдХ рдЙрджрд╛рд╣рд░рдг рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдЗрдВрдЯрд░рдлрд╝реЗрд╕ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рддрдХрдиреАрдХреЛрдВ рдкрд░ рд╡рд┐рдЪрд╛рд░ рдХрд░реВрдВрдЧрд╛ред рдПрдХ рдмрдЯрди рдкрд░ рдХреНрд▓рд┐рдХ рдХрд░рдиреЗ рдкрд░ рдЖрд╡реЗрджрди рджреЛрд╕реНрддреЛрдВ рдХреА рдПрдХ рд╕реВрдЪреА рджрд┐рдЦрд╛рддрд╛ рд╣реИред

рдЗрд╕рдореЗрдВ рддреАрди рднрд╛рдЧ рд╣реЛрддреЗ рд╣реИрдВ:

  1. рдШрдЯрдХ рдХрд╕реНрдЯрдо UI рдШрдЯрдХ рд╣реИрдВ, рдЕрд░реНрдерд╛рддреН, рдХреЛрдб рдХреЗрд╡рд▓ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдЗрдВрдЯрд░рдлрд╝реЗрд╕ рд╕реЗ рд╕рдВрдмрдВрдзрд┐рдд рд╣реИред
  2. рдбреЗрдореЛ рдПрдкреНрд▓рд┐рдХреЗрд╢рди - рдбреЗрдореЛ рд╡реНрдпреВ рдореЙрдбрд▓ рдФрд░ рдЕрдиреНрдп рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдЗрдВрдЯрд░рдлрд╝реЗрд╕ рдЗрдХрд╛рдЗрдпрд╛рдВ рдЬрд┐рдирдХреЗ рдкрд╛рд╕ рдХреЗрд╡рд▓ рдпреВрдЖрдИ рдирд┐рд░реНрднрд░рддрд╛рдПрдВ рд╣реИрдВред
  3. рд╡рд╛рд╕реНрддрд╡рд┐рдХ рдЕрдиреБрдкреНрд░рдпреЛрдЧ рджреГрд╢реНрдп рдореЙрдбрд▓ рдФрд░ рдЕрдиреНрдп рдЗрдХрд╛рдЗрдпрд╛рдБ рд╣реИрдВ рдЬрд┐рдирдореЗрдВ рд╡рд┐рд╢рд┐рд╖реНрдЯ рдирд┐рд░реНрднрд░рддрд╛ рдФрд░ рддрд░реНрдХ рд╣реЛ рд╕рдХрддреЗ рд╣реИрдВред

рдРрд╕рд╛ рдЕрд▓рдЧрд╛рд╡ рдХреНрдпреЛрдВ рд╣реИ? рдореИрдВ рдиреАрдЪреЗ рдЗрд╕ рдкреНрд░рд╢реНрди рдХрд╛ рдЙрддреНрддрд░ рджреВрдВрдЧрд╛, рд▓реЗрдХрд┐рди рдЕрднреА рдХреЗ рд▓рд┐рдП, рд╣рдорд╛рд░реЗ рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдХреЗ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдЗрдВрдЯрд░рдлрд╝реЗрд╕ рдХреЛ рджреЗрдЦреЗрдВ:


рдпрд╣ рдПрдХ рдкреВрд░реНрдг-рд╕реНрдХреНрд░реАрди рджреГрд╢реНрдп рдХреЗ рд╢реАрд░реНрд╖ рдкрд░ рд╕рд╛рдордЧреНрд░реА рдХреЗ рд╕рд╛рде рдПрдХ рдкреЙрдк-рдЕрдк рджреГрд╢реНрдп рд╣реИред рд╕рдм рдХреБрдЫ рд╕рд░рд▓ рд╣реИред

рдкрд░рд┐рдпреЛрдЬрдирд╛ рдХрд╛ рдкреВрд░реНрдг рд╕реНрд░реЛрдд рдХреЛрдб 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: рдШрдЯрдХ - рдлреВрдЯ рдбрд╛рд▓реЛ рдФрд░ рдЬреАрддреЛ


рд╣рдорд╛рд░рд╛ рдЙрджрд╛рд╣рд░рдг рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдЗрдВрдЯрд░рдлрд╝реЗрд╕ рдШрдЯрдХреЛрдВ рдореЗрдВ рд╡рд┐рднрд╛рдЬрд┐рдд рд╣реИ, рдЬрд┐рдирдореЗрдВ рд╕реЗ рдкреНрд░рддреНрдпреЗрдХ рдПрдХ рд╡рд┐рд╢рд┐рд╖реНрдЯ рдХрд╛рд░реНрдп рдХрд░рддрд╛ рд╣реИ, рдФрд░ рдирд╣реАрдВред

рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП:

  1. FriendsListHeaderView - рджреЛрд╕реНрддреЛрдВ рдФрд░ рдмрдВрдж рдмрдЯрди рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдЬрд╛рдирдХрд╛рд░реА рдкреНрд░рджрд░реНрд╢рд┐рдд рдХрд░рддрд╛ рд╣реИред
  2. FriendsListContentView - рдХреНрд▓рд┐рдХ рдХрд░рдиреЗ рдпреЛрдЧреНрдп рдХреЛрд╢рд┐рдХрд╛рдУрдВ рдХреЗ рд╕рд╛рде рджреЛрд╕реНрддреЛрдВ рдХреА рдПрдХ рд╕реВрдЪреА рдкреНрд░рджрд░реНрд╢рд┐рдд рдХрд░рддрд╛ рд╣реИ, рд╕реВрдЪреА рдХреЗ рдЕрдВрдд рддрдХ рдкрд╣реБрдВрдЪрдиреЗ рдкрд░ рд╕рд╛рдордЧреНрд░реА рдЧрддрд┐рд╢реАрд▓ рд░реВрдк рд╕реЗ рднрд░реА рд╣реБрдИ рд╣реИред
  3. 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) } 

рдпрд╣ рддрдХрдиреАрдХ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдЗрдВрдЯрд░рдлрд╝реЗрд╕ рдХреЛ рд╡реНрдпрд╛рд╡рд╕рд╛рдпрд┐рдХ рддрд░реНрдХ рд╕реЗ рдЕрд▓рдЧ рдХрд░рдиреЗ рдореЗрдВ рдорджрдж рдХрд░рддреА рд╣реИред рдЗрд╕рдХреЗ рдЕрд▓рд╛рд╡рд╛, рдпрд╣ рдЖрдкрдХреЛ рд╕рдВрдкреВрд░реНрдг рдпреВрдЖрдИ рдХреЛ рджреГрд╢реНрдп рдкрд░реАрдХреНрд╖рдгреЛрдВ рдХреЗ рд╕рд╛рде рдХрд╡рд░ рдХрд░рдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рджреЗрддрд╛ рд╣реИ, рдШрдЯрдХреЛрдВ рдХреЛ рдкрд░реАрдХреНрд╖рдг рдбреЗрдЯрд╛ рдкрд╛рд╕ рдХрд░ рд░рд╣рд╛ рд╣реИ! рдЗрд╕рд▓рд┐рдП, рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдЗрдВрдЯрд░рдлрд╝реЗрд╕ рдФрд░ рд╕рдВрдмрдВрдзрд┐рдд рд╡реНрдпрд╛рд╡рд╕рд╛рдпрд┐рдХ рддрд░реНрдХ рдХрд╛ рдкреГрдердХреНрдХрд░рдг рдкрд░рд┐рдпреЛрдЬрдирд╛ рдХреА рд╕рдлрд▓рддрд╛ рдХреЗ рд▓рд┐рдП рдорд╣рддреНрд╡рдкреВрд░реНрдг рд╣реИ, рдЪрд╛рд╣реЗ рд╡рд╣ рдПрдХ рд╕реНрдЯрд╛рд░реНрдЯрдЕрдк рд╣реЛ рдпрд╛ рдкрд╣рд▓реЗ рд╕реЗ рддреИрдпрд╛рд░ рдЙрддреНрдкрд╛рджред

рдирд┐рд╖реНрдХрд░реНрд╖


рдмреЗрд╢рдХ, рдпреЗ рдмрд╕ рдХреБрдЫ рддрдХрдиреАрдХреЛрдВ рдХрд╛ рдЗрд╕реНрддреЗрдорд╛рд▓ рдХрд┐рдпрд╛ рдЧрдпрд╛ рд╣реИ, рдФрд░ рд╡реЗ рд╕рднреА рд╕рдВрднрд╛рд╡рд┐рдд рдорд╛рдорд▓реЛрдВ рдХреЗ рд▓рд┐рдП рдПрдХ рд╕рд╛рд░реНрд╡рднреМрдорд┐рдХ рд╕рдорд╛рдзрд╛рди рдирд╣реАрдВ рд╣реИрдВред рдЗрд╕рд▓рд┐рдП, рдЙрдирдХрд╛ рдореВрд▓реНрдпрд╛рдВрдХрди рдХрд░рдиреЗ рдХреЗ рдмрд╛рдж рдЙрдирдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░реЗрдВ рдХрд┐ рдХреНрдпрд╛ рд╡реЗ рдЖрдкрдХреЗ рдФрд░ рдЖрдкрдХреА рдкрд░рд┐рдпреЛрдЬрдирд╛рдУрдВ рдХреЗ рд▓рд┐рдП рдЙрдкрдпреБрдХреНрдд рд╣реИрдВред

рдЕрдиреНрдп рд╡рд┐рдзрд┐рдпрд╛рдВ рд╣реИрдВ, рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рдЗрдВрдЯрд░рдлрд╝реЗрд╕ рдмрд┐рд▓реНрдбрд░ (рд╡реЗ рд╣рдорд╛рд░реЗ рдЕрдиреНрдп рд▓реЗрдЦ рдореЗрдВ рд╡рд░реНрдгрд┐рдд рд╣реИрдВ) рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рд╣реБрдП рдПрдХреНрд╕рдЖрдИрдмреА-рд╡рд┐рдиреНрдпрд╛рд╕ рдпреЛрдЧреНрдп рдпреВрдЖрдИ-рдШрдЯрдХ, рд▓реЗрдХрд┐рди рд╡рд┐рднрд┐рдиреНрди рдХрд╛рд░рдгреЛрдВ рд╕реЗ рдЙрдирдХрд╛ рдЙрдкрдпреЛрдЧ рдирд╣реАрдВ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред рдпрд╛рдж рд░рдЦреЗрдВ рдХрд┐ рд╕рднреА рдХреА рдЕрдкрдиреА рд░рд╛рдп рдФрд░ рдмрдбрд╝реА рддрд╕реНрд╡реАрд░ рдХреА рджреГрд╖реНрдЯрд┐ рд╣реИ, рдЗрд╕рд▓рд┐рдП, рдПрдХ рд╕рдлрд▓ рдкрд░рд┐рдпреЛрдЬрдирд╛ рдХреЛ рд╡рд┐рдХрд╕рд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рдЖрдкрдХреЛ рдЯреАрдо рдореЗрдВ рдПрдХ рдЖрдо рд╕рд╣рдорддрд┐ рдкрд░ рдЖрдирд╛ рдЪрд╛рд╣рд┐рдП рдФрд░ рдЕрдзрд┐рдХрд╛рдВрд╢ рдкрд░рд┐рджреГрд╢реНрдпреЛрдВ рдХреЗ рд▓рд┐рдП рд╕рдмрд╕реЗ рдЙрдкрдпреБрдХреНрдд рджреГрд╖реНрдЯрд┐рдХреЛрдг рдХрд╛ рдЪрдпрди рдХрд░рдирд╛ рдЪрд╛рд╣рд┐рдПред

рдЖрдкрдХреЗ рд╕рд╛рде рд╣реЛ рд╕рдХрддрд╛ рд╣реИ рд╕реНрд╡рд┐рдлреНрдЯ!

рд╕реВрддреНрд░реЛрдВ рдХрд╛ рдХрд╣рдирд╛ рд╣реИ

Source: https://habr.com/ru/post/hi421559/


All Articles