рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛рд╢реАрд▓ рдбреЗрдЯрд╛ рдкреНрд░рджрд░реНрд╢рди рдкреНрд░рдмрдВрдзрдХред рдкрд░рд┐рдЪрдп

рдпрд╣ ReactiveDataDisplayManager (RDDM) рд▓рд╛рдЗрдмреНрд░реЗрд░реА рдкрд░ рд▓реЗрдЦреЛрдВ рдХреА рдПрдХ рд╢реНрд░реГрдВрдЦрд▓рд╛ рдХрд╛ рдкрд╣рд▓рд╛ рднрд╛рдЧ рд╣реИред рдЗрд╕ рд▓реЗрдЦ рдореЗрдВ, рдореИрдВ рдЙрди рд╕рд╛рдорд╛рдиреНрдп рд╕рдорд╕реНрдпрд╛рдУрдВ рдХрд╛ рд╡рд░реНрдгрди рдХрд░реВрдБрдЧрд╛ рдЬрд┐рдиреНрд╣реЗрдВ рдореБрдЭреЗ "рдирд┐рдпрдорд┐рдд" рддрд╛рд▓рд┐рдХрд╛рдУрдВ рдХреЗ рд╕рд╛рде рдХрд╛рдо рдХрд░рдиреЗ рдХреЗ рд╕рд╛рде-рд╕рд╛рде RDDM рдХрд╛ рд╡рд┐рд╡рд░рдг рджреЗрдирд╛ рд╣реИред




рд╕рдорд╕реНрдпрд╛ 1. UITableViewDataSource


рд╢реБрд░реБрдЖрдд рдХреЗ рд▓рд┐рдП, рдЬрд┐рдореНрдореЗрджрд╛рд░рд┐рдпреЛрдВ, рдкреБрди: рдЙрдкрдпреЛрдЧ рдФрд░ рдЕрдиреНрдп рд╢рд╛рдВрдд рд╢рдмреНрджреЛрдВ рдХреЗ рдЖрд╡рдВрдЯрди рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рднреВрд▓ рдЬрд╛рдУред рдЖрдЗрдП рддрд╛рд▓рд┐рдХрд╛рдУрдВ рдХреЗ рд╕рд╛рде рд╕рд╛рдорд╛рдиреНрдп рдХрд╛рдо рджреЗрдЦреЗрдВ:

class ViewController: UIViewController { ... } extension ViewController: UITableViewDelegate { ... } extension ViewController: UITableViewDataSource { ... } 

рд╣рдо рд╕рдмрд╕реЗ рдЖрдо рд╡рд┐рдХрд▓реНрдк рдХрд╛ рд╡рд┐рд╢реНрд▓реЗрд╖рдг рдХрд░реЗрдВрдЧреЗред рд╣рдореЗрдВ рдХреНрдпрд╛ рд▓рд╛рдЧреВ рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ? рд╕рд╣реА рдврдВрдЧ рд╕реЗ, 3 UITableViewDataSource рддрд░реАрдХреЗ рдЖрдорддреМрд░ рдкрд░ рд▓рд╛рдЧреВ рдХрд┐рдП рдЬрд╛рддреЗ рд╣реИрдВ:

 func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int func numberOfSections(in tableView: UITableView) -> Int func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) 

рдЕрднреА рдХреЗ рд▓рд┐рдП, рд╣рдо рд╕рд╣рд╛рдпрдХ рд╡рд┐рдзрд┐рдпреЛрдВ ( numberOfSection рдЗрддреНрдпрд╛рджрд┐) рдкрд░ рдзреНрдпрд╛рди рдирд╣реАрдВ рджреЗрдВрдЧреЗ рдФрд░ рд╕рдмрд╕реЗ рджрд┐рд▓рдЪрд╕реНрдк рдПрдХ рдкрд░ рд╡рд┐рдЪрд╛рд░ рдХрд░реЗрдВрдЧреЗ - func tableView(tableView: UITableView, indexPath: IndexPath)

рдорд╛рди рд▓реЗрдВ рдХрд┐ рд╣рдо рдЙрддреНрдкрд╛рджреЛрдВ рдХреЗ рд╡рд┐рд╡рд░рдг рдХреЗ рд╕рд╛рде рдХреЛрд╢рд┐рдХрд╛рдУрдВ рдХреЗ рд╕рд╛рде рдПрдХ рддрд╛рд▓рд┐рдХрд╛ рднрд░рдирд╛ рдЪрд╛рд╣рддреЗ рд╣реИрдВ, рддреЛ рд╣рдорд╛рд░реА рд╡рд┐рдзрд┐ рдЗрд╕ рддрд░рд╣ рджрд┐рдЦрд╛рдИ рджреЗрдЧреА:

 func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) { let anyCell = tableView.dequeueReusableCell(withIdentifier: ProductCell.self, for: indexPath) guard let cell = anyCell as? ProductCell else { return UITableViewCell() } cell.configure(for: self.products[indexPath.row]) return cell } 

рдмрд╣реБрдд рдмрдврд╝рд┐рдпрд╛, рдпрд╣ рдореБрд╢реНрдХрд┐рд▓ рдирд╣реАрдВ рд╣реИред рдЕрдм, рдорд╛рди рд▓реЗрдВ рдХрд┐ рд╣рдорд╛рд░реЗ рдкрд╛рд╕ рдХрдИ рдкреНрд░рдХрд╛рд░ рдХреА рдХреЛрд╢рд┐рдХрд╛рдПрдБ рд╣реИрдВ, рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рддреАрди:

  • рдЙрддреНрдкрд╛рджреЛрдВ;
  • рд╢реЗрдпрд░реЛрдВ рдХреА рд╕реВрдЪреА;
  • рд╡рд┐рдЬреНрдЮрд╛рдкрдиред

рдЙрджрд╛рд╣рд░рдг рдХреА рд╕рд╛рджрдЧреА рдХреЗ рд▓рд┐рдП, рд╣рдо рд╕реЗрд▓ рдХреЛ getCell рд╡рд┐рдзрд┐ рдкреНрд░рд╛рдкреНрдд рдХрд░рддреЗ рд╣реИрдВ:

 func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) { switch indexPath.row { case 0: guard let cell: PromoCell = self.getCell() else { return UITableViewCell() } cell.configure(self.promo) return cell case 1: guard let cell: AdCell = self.getCell() else { return UITableViewCell() } cell.configure(self.ad) return cell default: guard let cell: AdCell = self.getCell() else { return UITableViewCell() } cell.configure(self.products[indexPath.row - 2]) return cell } } 

рдХрд┐рд╕реА рддрд░рд╣ рдмрд╣реБрдд рдХреЛрдбред рдХрд▓реНрдкрдирд╛ рдХрд░реЗрдВ рдХрд┐ рд╣рдо рд╕реЗрдЯрд┐рдВрдЧреНрд╕ рд╕реНрдХреНрд░реАрди рдмрдирд╛рдирд╛ рдЪрд╛рд╣рддреЗ рд╣реИрдВред рд╡рд╣рд╛рдБ рдХреНрдпрд╛ рд╣реЛрдЧрд╛?

  • рдПрдХ рдЕрд╡рддрд╛рд░ рдХреЗ рд╕рд╛рде рдПрдХ рд╕реЗрд▓ рдХреИрдк;
  • рд╕рдВрдХреНрд░рдордг рдХреЗ рд╕рд╛рде рдХреЛрд╢рд┐рдХрд╛рдУрдВ рдХрд╛ рдПрдХ рд╕реЗрдЯ "рдЧрд╣рд░рд╛рдИ рдореЗрдВ";
  • рд╕реНрд╡рд┐рдЪ рдХреЗ рд╕рд╛рде рд╕реЗрд▓ (рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рдкрд┐рди рдХреЛрдб рджреНрд╡рд╛рд░рд╛ рдЗрдирдкреБрдЯ рдХреЛ рд╕рдХреНрд╖рдо / рдЕрдХреНрд╖рдо рдХрд░реЗрдВ);
  • рдЬрд╛рдирдХрд╛рд░реА рдХреЗ рд╕рд╛рде рд╕реЗрд▓ (рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рдПрдХ рд╕реЗрд▓, рдЬрд┐рд╕ рдкрд░ рдПрдХ рдлреЛрди, рдИрдореЗрд▓, рдЬреЛ рднреА рд╣реЛрдЧрд╛);
  • рд╡реНрдпрдХреНрддрд┐рдЧрдд рдкреНрд░рд╕реНрддрд╛рд╡ред

рдЗрд╕рдХреЗ рдЕрд▓рд╛рд╡рд╛, рдЖрджреЗрд╢ рд╕реЗрдЯ рд╣реИред рдПрдХ рдмреЗрд╣рддрд░реАрди рддрд░реАрдХрд╛ рд╕рд╛рдордиреЗ рдЖрдПрдЧрд╛ ...

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

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

рд╡реИрд╕реЗ, рдЙрд╕рдХреЗ рдмрд╛рдж, рдХрд▓реНрдкрдирд╛ рдХрд░реЗрдВ рдХрд┐ рдпрджрд┐ рдЖрдк рдХрд╛рдо рдХрд░рддреЗ рд╣реИрдВ рддреЛ рдЖрдк рдЕрдкрдиреЗ рдХреЛрдб рдХреЛ рдХреНрдпрд╛ рдЬреЛрдбрд╝рдирд╛ / рд╣рдЯрд╛рдирд╛ рдЪрд╛рд╣реЗрдВрдЧреЗред рдпрд╣ рдмрд╣реБрдд рдЕрдЪреНрдЫрд╛ рдирд╣реАрдВ рд▓рдЧреЗрдЧрд╛ рдХреНрдпреЛрдВрдХрд┐ рд╣рдо ViewController рдФрд░ рдХреЛрд╢рд┐рдХрд╛рдУрдВ рдХреА рд╕рдВрдЦреНрдпрд╛ рдореЗрдВ рд╕рдВрдЧреНрд░рд╣реАрдд рдбреЗрдЯрд╛ рдХреА рд╕реНрдерд┐рд░рддрд╛ рдХреА рд╕реНрд╡рддрдВрддреНрд░ рд░реВрдк рд╕реЗ рдирд┐рдЧрд░рд╛рдиреА рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдордЬрдмреВрд░ рд╣реЛрдВрдЧреЗред

рд╕рдорд╕реНрдпрд╛рдПрдВ:

  • рдпрджрд┐ рд╡рд┐рднрд┐рдиреНрди рдкреНрд░рдХрд╛рд░ рдХреА рдХреЛрд╢рд┐рдХрд╛рдПрдВ рд╣реИрдВ, рддреЛ рдХреЛрдб рдиреВрдбрд▓ рдЬреИрд╕рд╛ рд╣реЛ рдЬрд╛рддрд╛ рд╣реИ;
  • рдХреЛрд╢рд┐рдХрд╛рдУрдВ рд╕реЗ рдШрдЯрдирд╛рдУрдВ рдХреЛ рд╕рдВрднрд╛рд▓рдиреЗ рдХреЗ рд╕рд╛рде рдХрдИ рд╕рдорд╕реНрдпрд╛рдПрдВ рд╣реИрдВ;
  • рдорд╛рдорд▓реЗ рдореЗрдВ рдмрджрд╕реВрд░рдд рдХреЛрдб рдЖрдкрдХреЛ рддрд╛рд▓рд┐рдХрд╛ рдХреА рд╕реНрдерд┐рддрд┐ рдХреЛ рдмрджрд▓рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИред

рд╕рдорд╕реНрдпрд╛ 2. рдорд╛рдЗрдВрдбрд╕реЗрдЯ


рд╢рд╛рдВрдд рд╢рдмреНрджреЛрдВ рдХрд╛ рд╕рдордп рдЕрднреА рдирд╣реАрдВ рдЖрдпрд╛ рд╣реИред
рдЖрдЗрдП рджреЗрдЦреЗрдВ рдХрд┐ рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдХреИрд╕реЗ рдХрд╛рдо рдХрд░рддрд╛ рд╣реИ, рдпрд╛ рдмрд▓реНрдХрд┐, рд╕реНрдХреНрд░реАрди рдкрд░ рдбреЗрдЯрд╛ рдХреИрд╕реЗ рджрд┐рдЦрд╛рдИ рджреЗрддрд╛ рд╣реИред рд╣рдо рд╣рдореЗрд╢рд╛ рдЗрд╕ рдкреНрд░рдХреНрд░рд┐рдпрд╛ рдХреЛ рдХреНрд░рдорд┐рдХ рд░реВрдк рд╕реЗ рдкреНрд░рд╕реНрддреБрдд рдХрд░рддреЗ рд╣реИрдВред рдареАрдХ рд╣реИ, рдХрдо рдпрд╛ рдЬреНрдпрд╛рджрд╛:

  1. рдиреЗрдЯрд╡рд░реНрдХ рд╕реЗ рдбреЗрдЯрд╛ рдкреНрд░рд╛рдкреНрдд рдХрд░реЗрдВ;
  2. рдкреНрд░рдХреНрд░рд┐рдпрд╛ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП;
  3. рдЗрд╕ рдбреЗрдЯрд╛ рдХреЛ рд╕реНрдХреНрд░реАрди рдкрд░ рдкреНрд░рджрд░реНрд╢рд┐рдд рдХрд░реЗрдВред

рд▓реЗрдХрд┐рди рдХреНрдпрд╛ рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ рдРрд╕рд╛ рд╣реИ? рдирд╣реАрдВ! рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ, рд╣рдо рдпрд╣ рдХрд░рддреЗ рд╣реИрдВ:

  1. рдиреЗрдЯрд╡рд░реНрдХ рд╕реЗ рдбреЗрдЯрд╛ рдкреНрд░рд╛рдкреНрдд рдХрд░реЗрдВ;
  2. рдкреНрд░рдХреНрд░рд┐рдпрд╛ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП;
  3. ViewController рдореЙрдбрд▓ рдХреЗ рдЕрдВрджрд░ рд╕рд╣реЗрдЬреЗрдВ;
  4. рдХреБрдЫ рд╕реНрдХреНрд░реАрди рд░рд┐рдлреНрд░реЗрд╢ рд╣реЛрдиреЗ рдХрд╛ рдХрд╛рд░рдг рдмрдирддрд╛ рд╣реИ;
  5. рд╕рд╣реЗрдЬреЗ рдЧрдП рдореЙрдбрд▓ рдХреЛ рдХреЛрд╢рд┐рдХрд╛рдУрдВ рдореЗрдВ рдмрджрд▓ рджрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ;
  6. рд╕реНрдХреНрд░реАрди рдкрд░ рдбреЗрдЯрд╛ рдкреНрд░рджрд░реНрд╢рд┐рдд рд╣реЛрддрд╛ рд╣реИред

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

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

рд╕рдорд╕реНрдпрд╛рдПрдВ:

  • рдпреВрдЖрдИ рдкрд░ рдбреЗрдЯрд╛ рдкреНрд░рд╕рдВрд╕реНрдХрд░рдг рдФрд░ рдЗрд╕рдХреЗ рдкреНрд░рджрд░реНрд╢рди рдХреЗ рдмреАрдЪ рд╕реНрдкрд╖реНрдЯ рд╕рдВрдмрдВрдз рдЦреЛ рдЧрдпрд╛ рд╣реИ;
  • рд╕реЗрд▓ рдХреЙрдиреНрдлрд╝рд┐рдЧрд░реЗрд╢рди рд╡рд┐рднрд┐рдиреНрди рднрд╛рдЧреЛрдВ рдореЗрдВ рдЯреВрдЯ рдЬрд╛рддрд╛ рд╣реИред

рд╡рд┐рдЪрд╛рд░


рдЬрдЯрд┐рд▓ рд╕реНрдХреНрд░реАрди рдкрд░ рд╕реВрдЪреАрдмрджреНрдз рд╕рдорд╕реНрдпрд╛рдПрдВ рд╕рд┐рд░рджрд░реНрдж рдФрд░ рдЪрд╛рдп рдХреЗ рд▓рд┐рдП рдЬрд╛рдиреЗ рдХреА рддреАрд╡реНрд░ рдЗрдЪреНрдЫрд╛ рдХрд╛ рдХрд╛рд░рдг рдмрдирддреА рд╣реИрдВред

рд╕рдмрд╕реЗ рдкрд╣рд▓реЗ, рдореИрдВ рд▓рдЧрд╛рддрд╛рд░ рдкреНрд░рддрд┐рдирд┐рдзрд┐ рд╡рд┐рдзрд┐рдпреЛрдВ рдХреЛ рд▓рд╛рдЧреВ рдирд╣реАрдВ рдХрд░рдирд╛ рдЪрд╛рд╣рддрд╛ред рд╕реНрдкрд╖реНрдЯ рд╕рдорд╛рдзрд╛рди рдПрдХ рд╡рд╕реНрддреБ рдмрдирд╛рдирд╛ рд╣реИ рдЬреЛ рдЗрд╕реЗ рд▓рд╛рдЧреВ рдХрд░реЗрдЧрд╛ред рдЖрдЧреЗ рд╣рдо рдХреБрдЫ рдРрд╕рд╛ рдХрд░реЗрдВрдЧреЗ:

 let displayManager = DisplayManager(self.tableView) 

рдмрд╣реБрдд рдмрдврд╝рд┐рдпрд╛ред рдЕрдм рдЖрдкрдХреЛ рдХрд┐рд╕реА рднреА рд╕реЗрд▓ рдХреЗ рд╕рд╛рде рдХрд╛рдо рдХрд░рдиреЗ рдореЗрдВ рд╕рдХреНрд╖рдо рд╣реЛрдиреЗ рдХреЗ рд▓рд┐рдП рдСрдмреНрдЬреЗрдХреНрдЯ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ, рдЬрдмрдХрд┐ рдЗрди рд╕реЗрд▓ рдХреЗ рдХреЙрдиреНрдлрд╝рд┐рдЧрд░реЗрд╢рди рдХреЛ рдХрд╣реАрдВ рдФрд░ рд╕реНрдерд╛рдирд╛рдВрддрд░рд┐рдд рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИред

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

рдЗрд╕ рдорд╛рдорд▓реЗ рдореЗрдВ, рд╣рдорд╛рд░реЗ рдкрд╛рд╕ рдПрдХ рдРрд╕реА рд╡рд╕реНрддреБ рд╣реЛрдЧреА рдЬрд┐рд╕рдореЗрдВ рджреЛ рдЕрд▓рдЧ-рдЕрд▓рдЧ рдЗрдВрдЯрд░рдлреЗрд╕ рд╣реЛрдВрдЧреЗ:

  1. UITableView рдЙрджрд╛рд╣рд░рдг рдЬрдирд░реЗрд╢рди рдЗрдВрдЯрд░рдлрд╝реЗрд╕ рд╣рдорд╛рд░реЗ DisplayManager рдХреЗ рд▓рд┐рдП рд╣реИред
  2. рдкреНрд░рд╕реНрддреБрддрд┐рдХрд░рдг, рд╕рджрд╕реНрдпрддрд╛ рдФрд░ рдХреЙрдиреНрдлрд╝рд┐рдЧрд░реЗрд╢рди рдЗрдВрдЯрд░рдлрд╝реЗрд╕ - рдкреНрд░рд╕реНрддреБрддрдХрд░реНрддрд╛ рдпрд╛ ViewController рдХреЗ рд▓рд┐рдПред

рдЗрд╕ рд╡рд╕реНрддреБ рдХреЛ рд╣рдо рдЬрдирд░реЗрдЯрд░ рдХрд╣рддреЗ рд╣реИрдВред рддрдм рдореЗрдЬ рдХреЗ рд▓рд┐рдП рд╣рдорд╛рд░рд╛ рдЬрдирд░реЗрдЯрд░ рдПрдХ рд╕реЗрд▓ рд╣реИ, рдФрд░ рдмрд╛рдХреА рд╕рдм рдХреЗ рд▓рд┐рдП - рдПрдХ рдпреВрдЖрдИ рдФрд░ рдкреНрд░рдХреНрд░рд┐рдпрд╛ рдХреА рдШрдЯрдирд╛рдУрдВ рдкрд░ рдбреЗрдЯрд╛ рдкреЗрд╢ рдХрд░рдиреЗ рдХрд╛ рдПрдХ рддрд░реАрдХрд╛ред

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

рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди


 public protocol TableCellGenerator: class { var identifier: UITableViewCell.Type { get } var cellHeight: CGFloat { get } var estimatedCellHeight: CGFloat? { get } func generate(tableView: UITableView, for indexPath: IndexPath) -> UITableViewCell func registerCell(in tableView: UITableView) } public protocol ViewBuilder { associatedtype ViewType: UIView func build(view: ViewType) } 

рдРрд╕реЗ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рдХреЗ рд╕рд╛рде, рд╣рдо рдбрд┐рдлрд╝реЙрд▓реНрдЯ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ:

 public extension TableCellGenerator where Self: ViewBuilder { func generate(tableView: UITableView, for indexPath: IndexPath) -> UITableViewCell { guard let cell = tableView.dequeueReusableCell(withIdentifier: self.identifier.nameOfClass, for: indexPath) as? Self.ViewType else { return UITableViewCell() } self.build(view: cell) return cell as? UITableViewCell ?? UITableViewCell() } func registerCell(in tableView: UITableView) { tableView.registerNib(self.identifier) } }<source lang="swift"> 

рдореИрдВ рдПрдХ рдЫреЛрдЯреЗ рдЬрдирд░реЗрдЯрд░ рдХрд╛ рдПрдХ рдЙрджрд╛рд╣рд░рдг рджреВрдВрдЧрд╛:

 final class FamilyCellGenerator { private var cell: FamilyCell? private var family: Family? var didTapPerson: ((Person) -> Void)? func show(family: Family) { self.family = family cell?.fill(with: family) } func showLoading() { self.family = nil cell?.showLoading() } } extension FamilyCellGenerator: TableCellGenerator { var identifier: UITableViewCell.Type { return FamilyCell.self } } extension FamilyCellGenerator: ViewBuilder { func build(view: FamilyCell) { self.cell = view view.selectionStyle = .none view.didTapPerson = { [weak self] person in self?.didTapPerson?(person) } if let family = self.family { view.fill(with: family) } else { view.showLoading() } } } 

рдпрд╣рд╛рдБ рд╣рдо рд╡рд┐рдиреНрдпрд╛рд╕ рдФрд░ рд╕рджрд╕реНрдпрддрд╛ рджреЛрдиреЛрдВ рдХреЛ рдЫрд┐рдкрд╛рддреЗ рд╣реИрдВред рдзреНрдпрд╛рди рджреЗрдВ рдХрд┐ рдЕрдм рд╣рдорд╛рд░реЗ рдкрд╛рд╕ рдПрдХ рдРрд╕реА рдЬрдЧрд╣ рд╣реИ рдЬрд╣рд╛рдВ рд╣рдо рд░рд╛рдЬреНрдп рдХреЛ рдПрдирдХреИрдкреНрд╕реБрд▓реЗрдЯ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ (рдХреНрдпреЛрдВрдХрд┐ рд╕реЗрд▓ рдореЗрдВ рд░рд╛рдЬреНрдп рдХреЛ рдЗрдирдХреИрдкреНрд╕реБрд▓реЗрдЯ рдХрд░рдирд╛ рдЕрд╕рдВрднрд╡ рд╣реИ рдХреНрдпреЛрдВрдХрд┐ рдпрд╣ рдЯреЗрдмрд▓ рджреНрд╡рд╛рд░рд╛ рдкреБрди: рдЙрдкрдпреЛрдЧ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ)ред рдФрд░ рдЙрдиреНрд╣реЗрдВ рд╕реЗрд▓ рдореЗрдВ рдбреЗрдЯрд╛ рдмрджрд▓рдиреЗ рдХрд╛ рдЕрд╡рд╕рд░ рднреА рдорд┐рд▓рд╛ "рдордХреНрдЦреА рдкрд░ред"

self.cell = view рдзреНрдпрд╛рди self.cell = view ред self.cell = view ред рд╣рдордиреЗ рд╕реЗрд▓ рдХреЛ рдпрд╛рдж рдХрд┐рдпрд╛ рдФрд░ рдЕрдм рд╣рдо рдЗрд╕ рд╕реЗрд▓ рдХреЛ рдлрд┐рд░ рд╕реЗ рд▓реЛрдб рдХрд┐рдП рдмрд┐рдирд╛ рдбреЗрдЯрд╛ рдХреЛ рдЕрдкрдбреЗрдЯ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред рдпрд╣ рдПрдХ рдЙрдкрдпреЛрдЧреА рд╡рд┐рд╢реЗрд╖рддрд╛ рд╣реИред

рд▓реЗрдХрд┐рди рдореИрдВ рд╡рд┐рдЪрд▓рд┐рдд рдерд╛ред рдЪреВрдБрдХрд┐ рд╣рдорд╛рд░реЗ рдкрд╛рд╕ рдЬрдирд░реЗрдЯрд░ рджреНрд╡рд╛рд░рд╛ рдкреНрд░рд╕реНрддреБрдд рдХреЛрдИ рднреА рд╕реЗрд▓ рд╣реЛ рд╕рдХрддрд╛ рд╣реИ, рд╣рдо рдЕрдкрдиреЗ DisplayManager рдХреЗ рдЗрдВрдЯрд░рдлрд╝реЗрд╕ рдХреЛ рдереЛрдбрд╝рд╛ рдФрд░ рд╕реБрдВрджрд░ рдмрдирд╛ рд╕рдХрддреЗ рд╣реИрдВред

 public protocol DataDisplayManager: class { associatedtype CollectionType associatedtype CellGeneratorType associatedtype HeaderGeneratorType init(collection: CollectionType) func forceRefill() func addSectionHeaderGenerator(_ generator: HeaderGeneratorType) func addCellGenerator(_ generator: CellGeneratorType) func addCellGenerators(_ generators: [CellGeneratorType], after: CellGeneratorType) func addCellGenerator(_ generator: CellGeneratorType, after: CellGeneratorType) func addCellGenerators(_ generators: [CellGeneratorType]) func update(generators: [CellGeneratorType]) func clearHeaderGenerators() func clearCellGenerators() } 

рдпрд╣ рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ рд╕рднреА рдирд╣реАрдВ рд╣реИред рд╣рдо рдЬрдирд░реЗрдЯрд░ рдХреЛ рд╕рд╣реА рд╕реНрдерд╛рдиреЛрдВ рдкрд░ рд╕рдореНрдорд┐рд▓рд┐рдд рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ рдпрд╛ рдЙрдиреНрд╣реЗрдВ рд╣рдЯрд╛ рд╕рдХрддреЗ рд╣реИрдВред

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

рдкрд░рд┐рдгрд╛рдо


рд╕реЗрд▓ рдХрд╛ рдХрд╛рдо рдЕрдм рдХреИрд╕реЗ рджрд┐рдЦреЗрдЧрд╛:

 class ViewController: UIViewController { func update(data: [Products]) { let gens = data.map { ProductCellGenerator($0) } self.ddm.addGenerators(gens) } } 

рдпрд╛ рдпрд╣рд╛рдБ:

 class ViewController: UIViewController { func update(fields: [Field]) { let gens = fields.map { field switch field.type { case .phone: let gen = PhoneCellGenerator(item) gen.didUpdate = { self.updatePhone($0) } return gen case .date: let gen = DateInputCellGenerator(item) gen.didTap = { self.showPicker() } return gen case .dropdown: let gen = DropdownCellGenerator(item) gen.didTap = { self.showDropdown(item) } return gen } } let splitter = SplitterGenerator() self.ddm.addGenerator(splitter) self.ddm.addGenerators(gens) self.ddm.addGenerator(splitter) } } 

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

RDDM рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдХреЗ рдирд┐рдпрдо:

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

рдпрд╣рд╛рдВ рдХреЗ рд╕реВрддреНрд░

рдЖрдкрдХрд╛ рдзреНрдпрд╛рди рдХреЗ рд▓рд┐рдП рдзрдиреНрдпрд╡рд╛рдж!

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


All Articles