рд╕рдВрдпреЛрдЬрди 5 рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдФрд░ рд╕реНрд╡рд┐рдлреНрдЯрдпреВрдЖрдИ рдореЗрдВ рдЙрдирдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рд╕реНрд╡рд┐рдлреНрдЯ 5 рдореЗрдВ HTTP рдЕрдиреБрд░реЛрдз рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЖрдзреБрдирд┐рдХ рдХреЛрдбред рднрд╛рдЧ 1



рдХреНрд╡реЗрд░реА HTTPрдЖрдк рдЬрдм рд╡рд┐рдХрд╛рд╕рд╢реАрд▓ рдкреНрд░рд╛рдкреНрдд рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╕рдмрд╕реЗ рдорд╣рддреНрд╡рдкреВрд░реНрдг рдХреМрд╢рд▓ рдореЗрдВ рд╕реЗ рдПрдХ рд╣реИ iOSрдЕрдиреБрдкреНрд░рдпреЛрдЧреЛрдВред рдкрд╣рд▓реЗ рдХреЗ рд╕рдВрд╕реНрдХрд░рдгреЛрдВ рдореЗрдВ Swift(рд╕рдВрд╕реНрдХрд░рдг 5 рд╕реЗ рдкрд╣рд▓реЗ), рднрд▓реЗ рд╣реА рдЖрдкрдиреЗ рд╕реНрдХреНрд░реИрдЪ рд╕реЗ рдЗрди рдЕрдиреБрд░реЛрдзреЛрдВ рдХреЛ рдЙрддреНрдкрдиреНрди рдХрд┐рдпрд╛ рд╣реЛ рдпрд╛ рдЕрдЪреНрдЫреА рддрд░рд╣ рд╕реЗ рдЬреНрдЮрд╛рдд рдЕрд▓реНрдореЛрдлрд╛рдпрд░ рдлреНрд░реЗрдорд╡рд░реНрдХ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ , рдЖрдкрдиреЗ рдЬрдЯрд┐рд▓ рдФрд░ рднреНрд░рдорд┐рдд рдХреЛрдб рдХреЛ callback рдкреНрд░рдХрд╛рд░  рд╕реЗ рд╕рдорд╛рдкреНрдд рдХрд░ рджрд┐рдпрд╛ completionHandler: @escaping(Result<T, APIError>) -> Voidред рдореМрдЬреВрджрд╛ рдХреЗ рд╕рд╛рде рд╕рдВрдпреЛрдЬрди рдХреЗ рд░реВрдк рдореЗрдВ рдХрд╛рд░реНрдпрд╛рддреНрдордХ рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛рд╢реАрд▓ рдкреНрд░реЛрдЧреНрд░рд╛рдорд┐рдВрдЧ рдХреЗ рдирдП рдврд╛рдВрдЪреЗ

рдореЗрдВ рдЙрдкрд╕реНрдерд┐рддрд┐ , рдФрд░ рдЖрдкрдХреЛ рдЗрдВрдЯрд░рдиреЗрдЯ рд╕реЗ рдбреЗрдЯрд╛ рдкреНрд░рд╛рдкреНрдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдмрд╣реБрдд рдХреЙрдореНрдкреИрдХреНрдЯ рдХреЛрдб рд╕реНрд╡рддрдВрддреНрд░ рд▓реЗрдЦрди рдХреЗ рд▓рд┐рдП рдЖрд╡рд╢реНрдпрдХ рд╕рднреА рдЙрдкрдХрд░рдг рдкреНрд░рджрд╛рди рдХрд░рддрд╛ рд╣реИред рдЗрд╕ рд▓реЗрдЦ рдореЗрдВ, рдЕрд╡рдзрд╛рд░рдгрд╛ рдХреЗ рдЕрдиреБрд╕рд╛рд░, рд╣рдо "рдкреНрд░рдХрд╛рд╢рдХ" рдмрдирд╛рдПрдВрдЧреЗSwift 5CombineURLSessionCodable

CombinePublisherрдЗрдВрдЯрд░рдиреЗрдЯ рд╕реЗ рдбреЗрдЯрд╛ рдХрд╛ рдЪрдпрди рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рдЬрд┐рд╕реЗ рд╣рдо рднрд╡рд┐рд╖реНрдп рдореЗрдВ рдЖрд╕рд╛рдиреА рд╕реЗ "рд╕рдмреНрд╕рдХреНрд░рд╛рдЗрдм" рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ рдФрд░ рдЙрдкрдпреЛрдЧ рдХреЗ UIрд╕рд╛рде UIKitрдФрд░ рд╕рд╣рд╛рдпрддрд╛ рдХреЗ рд╕рд╛рде  рдбрд┐рдЬрд╝рд╛рдЗрди рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ  SwiftUIред

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

ObservableObject@Published рдЧреБрдг рддреБрд▓реНрдпрдХрд╛рд▓рд┐рдХ рдФрд░ / рдпрд╛ рдЕрддреБрд▓реНрдпрдХрд╛рд▓рд┐рдХ рдЕрдиреНрдп рдкрд░рд┐рд╡рд░реНрддрди рдХрд╛ рдкрд░рд┐рдгрд╛рдо рд╣реИ @Published  рдЬреЛ рд╕реАрдзреЗ (рдпреВрдЬрд░ рдЗрдВрдЯрд░рдлреЗрд╕ рдХреЗ рдЗрд╕ рддрд░рд╣ рдХреЗ "рд╕рдХреНрд░рд┐рдп" рддрддреНрд╡реЛрдВ рдмрджрд▓рд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ рдЧреБрдг UIрдкрд╛рда рдмреЙрдХреНрд╕ рдХреЗ рд░реВрдк рдореЗрдВ) TextField, Picker, Stepper, ToggleрдЖрджрд┐

рдпрд╣ рд╕реНрдкрд╖реНрдЯ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдХрд┐ рдХреНрдпрд╛ рджрд╛рдВрд╡ рдкрд░ рд╣реИ, рдореИрдВ рд╡рд┐рд╢рд┐рд╖реНрдЯ рдЙрджрд╛рд╣рд░рдг рджреВрдВрдЧрд╛ред рдЕрдм рдХрдИ рд╕реЗрд╡рд╛рдПрдБ рдЬреИрд╕реЗ рдХрд┐ NewsAPI.org  рдФрд░ рд╣реИрдХрд░ рдиреНрдпреВрдЬрд╝ рд╕рдорд╛рдЪрд╛рд░ рдПрдЧреНрд░реАрдЧреЗрдЯрд░реНрд╕ рдХреА рдкреЗрд╢рдХрд╢ рдХрд░рддреЗ рд╣реИрдВ рдЬреЛ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛рдУрдВ рдХреЛ рдЙрдирдХреЗ рд╣рд┐рддреЛрдВ рдХреЗ рдЖрдзрд╛рд░ рдкрд░ рд▓реЗрдЦреЛрдВ рдХреЗ рд╡рд┐рднрд┐рдиреНрди рд╕реЗрдЯреЛрдВ рдХрд╛ рдЪрдпрди рдХрд░рдиреЗ рдХреА  рдкреЗрд╢рдХрд╢ рдХрд░рддреЗ рд╣реИрдВред NewsAPI.org рд╕рдорд╛рдЪрд╛рд░ рдПрдЧреНрд░реАрдЧреЗрдЯрд░ рдХреЗ рдорд╛рдорд▓реЗ рдореЗрдВ  , рдпрд╣ рдирд╡реАрдирддрдо рд╕рдорд╛рдЪрд╛рд░ рдпрд╛ рдХреБрдЫ рд╢реНрд░реЗрдгреА рдореЗрдВ рд╕рдорд╛рдЪрд╛рд░ рд╣реЛ рд╕рдХрддрд╛ рд╣реИ - "рдЦреЗрд▓", "рд╕реНрд╡рд╛рд╕реНрдереНрдп", "рд╡рд┐рдЬреНрдЮрд╛рди", "рдкреНрд░реМрджреНрдпреЛрдЧрд┐рдХреА", "рд╡реНрдпрд╛рдкрд╛рд░", рдпрд╛ рдПрдХ рд╡рд┐рд╢рд┐рд╖реНрдЯ рд╕реВрдЪрдирд╛ рд╕реНрд░реЛрдд "рд╕реАрдПрдирдПрди" рд╕реЗ рд╕рдорд╛рдЪрд╛рд░ред , рдПрдмреАрд╕реА рдиреНрдпреВрдЬ, рдмреНрд▓реВрдордмрд░реНрдЧ, рдЖрджрд┐ред рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдЖрдорддреМрд░ рдкрд░ рд╕реЗрд╡рд╛рдУрдВ рдХреЗ рд▓рд┐рдП рдЕрдкрдиреА рдЗрдЪреНрдЫрд╛рдУрдВ рдХреЛ "рдЙрд╕ рд░реВрдк рдореЗрдВ" рд╡реНрдпрдХреНрдд рдХрд░рддрд╛ рд╣реИ рдЬреЛ EndpointрдЙрд╕рдХреЗ рд▓рд┐рдП рдЖрд╡рд╢реНрдпрдХ рд░реВрдк рдмрдирд╛рддрд╛ рд╣реИ URLред

рддреЛ, рдврд╛рдВрдЪреЗ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ  Combine, рдЖрдк рдХрд░ рд╕рдХрддреЗ рд╣реИрдВObservableObject рдмрд╣реБрдд рдХреЙрдореНрдкреИрдХреНрдЯ рдХреЛрдб рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рд╡рд╛рд▓реА рдХрдХреНрд╖рд╛рдПрдВ (рдЬреНрдпрд╛рджрд╛рддрд░ рдорд╛рдорд▓реЛрдВ рдореЗрдВ 10-12 рд▓рд╛рдЗрдиреЛрдВ рд╕реЗ рдЕрдзрд┐рдХ рдирд╣реАрдВ) рдПрдХ рдмрд╛рд░ Endpoint"рдирд┐рд╖реНрдХреНрд░рд┐рдп" @Published рдЧреБрдгреЛрдВ рдХреЗ "рд╕рдХреНрд░рд┐рдп" @Published рдЧреБрдгреЛрдВ рдХреЗ "рд╕рдмреНрд╕рдХреНрд░рд┐рдкреНрд╢рди" рдХреЗ рд░реВрдк рдореЗрдВ рд▓реЗрдЦреЛрдВ рдХреА рд╕реВрдЪреА рдХрд╛ рдПрдХ рддреБрд▓реНрдпрдХрд╛рд▓рд┐рдХ рдФрд░ / рдпрд╛ рдЕрддреБрд▓реНрдпрдХрд╛рд▓рд┐рдХ рд░реВрдк рдмрдирд╛рдиреЗ рдХреЗ рд▓рд┐рдП  ред рдпрд╣ "рд╕рджрд╕реНрдпрддрд╛" ObservableObject рд╡рд░реНрдЧ рдЙрджрд╛рд╣рд░рдг рдХреЗ рдкреВрд░реЗ "рдЬреАрд╡рди рдЪрдХреНрд░" рдореЗрдВ рдорд╛рдиреНрдп рд╣реЛрдЧрд╛  ред рдФрд░ рдлрд┐рд░ SwiftUI рдЖрдк рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдХреЛ @Published рдлреЙрд░реНрдо рдореЗрдВ рдХреЗрд╡рд▓ "рд╕рдХреНрд░рд┐рдп" рдЧреБрдгреЛрдВ рдХреЛ рдкреНрд░рдмрдВрдзрд┐рдд рдХрд░рдиреЗ рдХрд╛ рдЕрд╡рд╕рд░ рджреЗрдВрдЧреЗ Endpoint, рдЕрд░реНрдерд╛рдд рд╡рд╣ рдХреНрдпрд╛ рджреЗрдЦрдирд╛ рдЪрд╛рд╣рддрд╛ рд╣реИ: рдХреНрдпрд╛ рдпрд╣ "рд╕реНрд╡рд╛рд╕реНрдереНрдп" рдЕрдиреБрднрд╛рдЧ рдореЗрдВ рдирд╡реАрдирддрдо рд╕рдорд╛рдЪрд╛рд░реЛрдВ рдпрд╛ рд▓реЗрдЦреЛрдВ рдХреЗ рд╕рд╛рде рд╣реЛрдЧрд╛ред рдЕрдкрдиреЗ рдЖрдк рдкрд░ "рд╕реНрд╡рд╛рд╕реНрдереНрдп" рдЕрдиреБрднрд╛рдЧ рдореЗрдВ рдирд╡реАрдирддрдо рд╕рдорд╛рдЪрд╛рд░реЛрдВ рдпрд╛ рд▓реЗрдЦреЛрдВ рдХреЗ рд╕рд╛рде рд▓реЗрдЦреЛрдВ рдХреА рдЙрдкрд╕реНрдерд┐рддрд┐ рдЖрдкрдХреЛ UI рдЗрди ObservableObject рдХрдХреНрд╖рд╛рдУрдВ рдФрд░ рдЙрдирдХреЗ "рдЕрдкреНрд░рдХрд╛рд╢рд┐рдд" рдЧреБрдгреЛрдВ рджреНрд╡рд╛рд░рд╛ рд╕реНрд╡рдд: рдкреНрд░рджрд╛рди рдХреА рдЬрд╛рдПрдЧреА  ред рдХреЛрдб рдореЗрдВSwiftUI рдЖрдкрдХреЛ рд▓реЗрдЦреЛрдВ рдХреЗ рдЪрдпрди рдХреЗ рд▓рд┐рдП рд╕реНрдкрд╖реНрдЯ рд░реВрдк рд╕реЗ рдЕрдиреБрд░реЛрдз рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рдирд╣реАрдВ рд╣реЛрдЧреА, рдХреНрдпреЛрдВрдХрд┐ ObservableObjectрднреВрдорд┐рдХрд╛ рдирд┐рднрд╛рдиреЗ рд╡рд╛рд▓реА рдХрдХреНрд╖рд╛рдПрдВ рд╕реНрдХреНрд░реАрди рдкрд░ рдЙрдирдХреЗ рд╕рд╣реА рдФрд░ рддреБрд▓реНрдпрдХрд╛рд▓рд┐рдХ рдкреНрд░рджрд░реНрд╢рди рдХреЗ рд▓рд┐рдП рдЬрд┐рдореНрдореЗрджрд╛рд░ рд╣реИрдВ  View Modelред

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

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

рд╣рдо NewsAPI.org рд╕рдорд╛рдЪрд╛рд░ рдПрдЧреНрд░реАрдЧреЗрдЯрд░ рдХреЗ рд╕рд╛рде рд╕рд╣рднрд╛рдЧрд┐рддрд╛ рдХрд░рдиреЗ рд╡рд╛рд▓реЗ рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдХреЛ рд╡рд┐рдХрд╕рд┐рдд рдХрд░рдХреЗ рдЕрдкрдиреА рд░рдгрдиреАрддрд┐ рдмрдирд╛рдирд╛ рд╢реБрд░реВ  рдХрд░реЗрдВрдЧреЗ ред рдореБрдЭреЗ рдХрд╣рдирд╛ рд╣реЛрдЧрд╛ рдХрд┐ рдЗрд╕ рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдореЗрдВ рдЗрд╕реЗ SwiftUIрдмрд┐рдирд╛ рдХрд┐рд╕реА рддрд╛рдордЭрд╛рдо рдХреЗ рдиреНрдпреВрдирддрдо рд╕реАрдорд╛ рддрдХ рдЗрд╕реНрддреЗрдорд╛рд▓ рдХрд┐рдпрд╛ рдЬрд╛рдПрдЧрд╛ рдФрд░ рдкреВрд░реА рддрд░рд╣ рд╕реЗ рдпрд╣ рджрд┐рдЦрд╛рдиреЗ рдХреЗ рд▓рд┐рдП рдХрд┐ CombineрдЗрд╕рдХреЗ "рдкреНрд░рдХрд╛рд╢рди" рдХреЗ рд╕рд╛рде рдХреИрд╕реЗ рд╣реЛрдЧрд╛PublisherрдФрд░ "рд╕рджрд╕реНрдпрддрд╛" SubscriptionрдкреНрд░рднрд╛рд╡рд┐рдд рд╣реЛрддреЗ рд╣реИрдВ UIред

рдпрд╣ рдЕрдиреБрд╢рдВрд╕рд╛ рдХреА рдЬрд╛рддреА рд╣реИ рдХрд┐ рдЖрдк NewsAPI.org рд╡реЗрдмрд╕рд╛рдЗрдЯ рдкрд░ рд░рдЬрд┐рд╕реНрдЯрд░ рдХрд░реЗрдВ рдФрд░ рд╡рд╣ рдХреБрдВрдЬреА рдкреНрд░рд╛рдкреНрдд рдХрд░реЗрдВ APIрдЬреЛ NewsAPI.org рд╕реЗрд╡рд╛ рдХреЗ рдХрд┐рд╕реА рднреА рдЕрдиреБрд░реЛрдз рдХреЛ рдкреВрд░рд╛ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЖрд╡рд╢реНрдпрдХ рд╣реИ ред рдЖрдкрдХреЛ рдЗрд╕реЗ рд╕рдВрд░рдЪрдирд╛ рдореЗрдВ NewsAPI.swift рдлрд╝рд╛рдЗрд▓ рдореЗрдВ рд░рдЦрдирд╛ рд╣реЛрдЧрд╛APIConstants ред

рдЗрд╕ рд▓реЗрдЦ рдХреЗ рд▓рд┐рдП рдЖрд╡реЗрджрди рдХреЛрдб Github рдкрд░ рд╣реИ ред

NewsAPI.org рд╕реЗрд╡рд╛ рдбреЗрдЯрд╛ рдореЙрдбрд▓ рдФрд░ рдПрдкреАрдЖрдИ


NewsAPI.org рд╕реЗрд╡рд╛  рдЖрдкрдХреЛ рд╡рд░реНрддрдорд╛рди рд╕рдорд╛рдЪрд╛рд░ рд▓реЗрдЦреЛрдВ [Article]рдФрд░ рдЙрдирдХреЗ рд╕реНрд░реЛрддреЛрдВ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдЬрд╛рдирдХрд╛рд░реА рдХрд╛ рдЪрдпрди рдХрд░рдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рджреЗрддреА рд╣реИ  [Source]ред рд╣рдорд╛рд░рд╛ рдбреЗрдЯрд╛ рдореЙрдбрд▓ рдмрд╣реБрдд рд╕рд░рд▓ рд╣реЛрдЧрд╛, рдпрд╣ Article.swift рдлрд╝рд╛рдЗрд▓ рдореЗрдВ рд╕реНрдерд┐рдд рд╣реИ  :

import Foundation

struct NewsResponse: Codable {
    let status: String?
    let totalResults: Int?
    let articles: [Article]
}

struct Article: Codable, Identifiable {
    let id = UUID()
    let title: String
    let description: String?
    let author: String?
    let urlToImage: String?
    let publishedAt: Date?
    let source: Source
}

struct SourcesResponse: Codable {
    let status: String
    let sources: [Source]
}

struct Source: Codable,Identifiable {
    let id: String?
    let name: String?
    let description: String?
    let country: String?
    let category: String?
    let url: String?
}

рд▓реЗрдЦ ArticleрдореЗрдВ рдкрд╣рдЪрд╛рдирдХрд░реНрддрд╛ id, рд╢реАрд░реНрд╖рдХ title, рд╡рд┐рд╡рд░рдг  description, рд▓реЗрдЦрдХ author, "рдЫрд╡рд┐" рдХрд╛ URL urlToImage, рдкреНрд░рдХрд╛рд╢рди рдХреА рддрд┐рдерд┐ рдФрд░ рдкреНрд░рдХрд╛рд╢рди publishedAtрдХрд╛ рд╕реНрд░реЛрдд рд╣реЛрдЧрд╛ sourceред рд▓реЗрдЦреЛрдВ рдХреЗ рдКрдкрд░ [Article]рдПрдХ рдРрдб рд╣реИ NewsResponse, рдЬрд┐рд╕рдореЗрдВ рд╣рдо рдХреЗрд╡рд▓ рд╕рдВрдкрддреНрддрд┐ рдореЗрдВ рд░реБрдЪрд┐ рд░рдЦреЗрдВрдЧреЗ articles, рдЬреЛ рдХрд┐ рд▓реЗрдЦреЛрдВ рдХреА рдПрдХ рд╕рд░рдгреА рд╣реИред рдЬрдбрд╝ рд╕рдВрд░рдЪрдирд╛ NewsResponseрдФрд░ рд╕рдВрд░рдЪрдирд╛  Articleрд╣реИрдВ CodableрдЬреЛ рд╣рдореЗрдВ рд╕рдЪрдореБрдЪ рдХреЛрдб рдХреА рджреЛ рдкрдВрдХреНрддрд┐рдпрд╛рдБ рдбрд┐рдХреЛрдбрд┐рдВрдЧ рдХрд░рдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рджреЗрдЧрд╛, JSONрдореЙрдбрд▓ рдореЗрдВ рдбреЗрдЯрд╛ред рд╕рдВрд░рдЪрдирд╛  Article рднреА рд╣реЛрдиреА рдЪрд╛рд╣рд┐рдП Identifiable, рдЕрдЧрд░ рд╣рдо [Article]рд╕реВрдЪреА List рдореЗрдВ рдПрдХ рд▓реЗрдЦ рдХреЗ рд░реВрдк  рдореЗрдВ рд▓реЗрдЦреЛрдВ рдХреА рдПрдХ рд╕рд░рдгреА рдкреНрд░рджрд░реНрд╢рд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЦреБрдж рдХреЛ рдЖрд╕рд╛рди рдмрдирд╛рдирд╛ рдЪрд╛рд╣рддреЗ рд╣реИрдВ SwiftUIред рдкреНрд░реЛрдЯреЛрдХреЙрд▓ рдХреЗ Identifiable рд▓рд┐рдП рдПрдХ рд╕рдВрдкрддреНрддрд┐ рдХреА рдЙрдкрд╕реНрдерд┐рддрд┐ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реЛрддреА рд╣реИidрдЬрд┐рд╕реЗ рд╣рдо рдПрдХ рдХреГрддреНрд░рд┐рдо рд╡рд┐рд╢рд┐рд╖реНрдЯ рдкрд╣рдЪрд╛рдирдХрд░реНрддрд╛ рдкреНрд░рджрд╛рди рдХрд░реЗрдВрдЧреЗ UUID()ред

рд╕реВрдЪрдирд╛ рд╕реНрд░реЛрдд  SourceрдореЗрдВ рдПрдХ рдкрд╣рдЪрд╛рдирдХрд░реНрддрд╛ id, рдирд╛рдо name, рд╡рд┐рд╡рд░рдг  description, рджреЗрд╢ country, рдкреНрд░рдХрд╛рд╢рди рд╕реНрд░реЛрдд рд╢реНрд░реЗрдгреА category, рд╕рд╛рдЗрдЯ URL рд╢рд╛рдорд┐рд▓ рд╣реЛрдВрдЧреЗ urlред рд╕реВрдЪрдирд╛ рд╕реНрд░реЛрддреЛрдВ рдХреЗ рдКрдкрд░  [Source] рдПрдХ рдРрдб  SourcesResponse-рдЗрди рд╣реИ рдЬрд┐рд╕рдореЗрдВ рд╣рдо рдХреЗрд╡рд▓ рдПрдХ рд╕рдВрдкрддреНрддрд┐ рдореЗрдВ рд░реБрдЪрд┐ рд░рдЦреЗрдВрдЧреЗ sources, рдЬреЛ рд╕реВрдЪрдирд╛ рд╕реНрд░реЛрддреЛрдВ рдХреА рдПрдХ рд╕рд░рдгреА рд╣реИред рдЬрдбрд╝ рд╕рдВрд░рдЪрдирд╛ SourcesResponseрдФрд░ рд╕рдВрд░рдЪрдирд╛  Sourceрд╣реИрдВ CodableрдЬреЛ рд╣рдореЗрдВ рдмрд╣реБрдд рдЖрд╕рд╛рдиреА рд╕реЗ рдбрд┐рдХреЛрдб рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЕрдиреБрдорддрд┐ рджреЗрдЧрд╛, JSONрдПрдХ рдореЙрдбрд▓ рдореЗрдВ рдбреЗрдЯрд╛ред рд╕рдВрд░рдЪрдирд╛  Source рднреА рд╣реЛрдирд╛ рдЪрд╛рд╣рд┐рдП Identifiable, рдЕрдЧрд░ рд╣рдо рд╕реВрдЪрдирд╛ рдХреЗ рд╕реВрддреНрд░реЛрдВ рдХреА рдПрдХ рд╕рд░рдгреА рдХреЗ рдкреНрд░рджрд░реНрд╢рди рдХреА рд╕реБрд╡рд┐рдзрд╛ рдХреЗ рд▓рд┐рдП рдЪрд╛рд╣рддреЗ рд╣реИрдВ  [Source]рдПрдХ рд╕реВрдЪреА рдХреЗ рд░реВрдк рдореЗрдВ  List рдореЗрдВSwiftUIред рдкреНрд░реЛрдЯреЛрдХреЙрд▓ рдХреЗ Identifiableрд▓рд┐рдП рдЙрд╕ рд╕рдВрдкрддреНрддрд┐ рдХреА рдЙрдкрд╕реНрдерд┐рддрд┐ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реЛрддреА рд╣реИ idрдЬреЛ рд╣рдорд╛рд░реЗ рдкрд╛рд╕ рдкрд╣рд▓реЗ рд╕реЗ рд╣реИ, рдЗрд╕рд▓рд┐рдП рд╣рдорд╕реЗ рдХреЛрдИ рдЕрддрд┐рд░рд┐рдХреНрдд рдкреНрд░рдпрд╛рд╕ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рдирд╣реАрдВ рд╣реЛрдЧреАред

рдЕрдм рд╡рд┐рдЪрд╛рд░ рдХрд░реЗрдВ рдХрд┐ рд╣рдореЗрдВ NewsAPI.orgAPI рд╕реЗрд╡рд╛ рдХреЗ рд▓рд┐рдП  рдХреНрдпрд╛ рдЪрд╛рд╣рд┐рдП  рдФрд░ рдЗрд╕реЗ NewsAPI.swift рдлрд╝рд╛рдЗрд▓ рдореЗрдВ рд░рдЦреЗрдВ  ред рд╣рдорд╛рд░рд╛ рдордзреНрдп рднрд╛рдЧ  рдПрдХ рд╡рд░реНрдЧ рд╣реИ рдЬреЛ NewsAPI.org рд╕рдорд╛рдЪрд╛рд░ рдПрдЧреНрд░реАрдЧреЗрдЯрд░ рд╕реЗ рдбреЗрдЯрд╛ рдХреЗ рдЪрдпрди рдХреЗ рд▓рд┐рдП рджреЛ рддрд░реАрдХреЗ рдкреНрд░рд╕реНрддреБрдд рдХрд░рддрд╛ рд╣реИ   - рд▓реЗрдЦ  рдФрд░ рд╕реВрдЪрдирд╛ рд╕реНрд░реЛрдд :APINewsAPI[Article] [Source]

  • fetchArticles (from endpoint: Endpoint) -> AnyPublisher<[Article], Never>  - [Article]рдкреИрд░рд╛рдореАрдЯрд░ рдХреЗ рдЖрдзрд╛рд░ рдкрд░ рд▓реЗрдЦреЛрдВ рдХрд╛ рдЪрдпрди  endpoint,
  • fetchSources (for country: String) -> AnyPublisher<[Source], Never>- [Source]рдХрд┐рд╕реА рд╡рд┐рд╢реЗрд╖ рджреЗрд╢ рдХреЗ рд▓рд┐рдП рд╕реВрдЪрдирд╛ рдХреЗ рд╕реНрд░реЛрддреЛрдВ рдХрд╛ рдЪрдпрди countryред

рдпреЗ рд╡рд┐рдзрд┐рдпрд╛рдВ рди рдХреЗрд╡рд▓ рд▓реЗрдЦреЛрдВ рдХреА  [Article] рдПрдХ рд╕рд░рдгреА рдпрд╛ рд╕реВрдЪрдирд╛ рд╕реНрд░реЛрддреЛрдВ рдХреА рдПрдХ рд╕рд░рдгреА  [Source], рдмрд▓реНрдХрд┐ Publisher рдирдП рдврд╛рдВрдЪреЗ рдХреЗ рд╕рдВрдмрдВрдзрд┐рдд "рдкреНрд░рдХрд╛рд╢рдХ" рдкрд░  рд▓реМрдЯрддреА рд╣реИрдВ Combineред рджреЛрдиреЛрдВ рдкреНрд░рдХрд╛рд╢рдХ рдХрд┐рд╕реА рднреА рддреНрд░реБрдЯрд┐ рдХреЛ рд╡рд╛рдкрд╕ рдирд╣реАрдВ рдХрд░рддреЗ рд╣реИрдВ - NeverрдФрд░ рдпрджрд┐ рдХреЛрдИ рдирдореВрдирд╛ рдпрд╛ рдХреЛрдбрд┐рдВрдЧ рддреНрд░реБрдЯрд┐ рдЕрднреА рднреА рд╣реБрдИ рд╣реИ, рддреЛ рд▓реЗрдЦреЛрдВ [Article]() рдпрд╛ рд╕реВрдЪрдирд╛ рд╕реНрд░реЛрддреЛрдВ рдХреЗ рдПрдХ рдЦрд╛рд▓реА рд╕рд░рдгреА рдХреЛ [Source]()рдмрд┐рдирд╛ рдХрд┐рд╕реА рд╕рдВрджреЗрд╢ рдХреЗ рд╡рд╛рдкрд╕ рдХрд░ рджрд┐рдпрд╛  рдЬрд╛рддрд╛ рд╣реИ  рдХреНрдпреЛрдВ рдпреЗ рд╕рд░рдгрд┐рдпрд╛рдБ рдЦрд╛рд▓реА рдереАрдВред 

рд╣рдо NewsAPI.org рд╕рд░реНрд╡рд░ рд╕реЗ рдХреМрди рд╕реЗ рд▓реЗрдЦ рдпрд╛ рдЬрд╛рдирдХрд╛рд░реА рдХрд╛ рд╕реНрд░реЛрдд рдЪреБрдирдирд╛ рдЪрд╛рд╣рддреЗ рд╣реИрдВ , рд╣рдо рдЧрдгрдирд╛ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рд╕рдВрдХреЗрдд рдХрд░реЗрдВрдЧреЗenum Endpoint:

enum Endpoint {
    case topHeadLines
    case articlesFromCategory(_ category: String)
    case articlesFromSource(_ source: String)
    case search (searchFilter: String)
    case sources (country: String)
    
    var baseURL:URL {URL(string: "https://newsapi.org/v2/")!}
    
    func path() -> String {
        switch self {
        case .topHeadLines, .articlesFromCategory:
            return "top-headlines"
        case .search,.articlesFromSource:
            return "everything"
        case .sources:
            return "sources"
        }
    }
}

рдпрд╣:

  • рдирд╡реАрдирддрдо рд╕рдорд╛рдЪрд╛рд░  .topHeadLines,
  • рдПрдХ рдирд┐рд╢реНрдЪрд┐рдд рд╢реНрд░реЗрдгреА рдХреА рдЦрдмрд░реЗрдВ (рдЦреЗрд▓, рд╕реНрд╡рд╕реНрде, рд╡рд┐рдЬреНрдЮрд╛рди, рд╡реНрдпрд╡рд╕рд╛рдп, рдкреНрд░реМрджреНрдпреЛрдЧрд┐рдХреА)  .articlesFromCategory(_ category: String),
  • рд╕реВрдЪрдирд╛ рдХреЗ рдПрдХ рд╡рд┐рд╢реЗрд╖ рд╕реНрд░реЛрдд (рд╕реАрдПрдирдПрди, рдПрдмреАрд╕реА рдиреНрдпреВрдЬ, рдлреЙрдХреНрд╕ рдиреНрдпреВрдЬ, рдЖрджрд┐) рд╕реЗ рд╕рдорд╛рдЪрд╛рд░  .articlesFromSource(_ source: String),
  • рдХреЛрдИ рднреА рд╕рдорд╛рдЪрд╛рд░  .search (searchFilter: String)рдЬреЛ рдПрдХ рдирд┐рд╢реНрдЪрд┐рдд рд╢рд░реНрдд рдХреЛ рдкреВрд░рд╛ рдХрд░рддрд╛ рд╣реИ searchFilter,
  • .sources (country:String)рдХрд┐рд╕реА рд╡рд┐рд╢реЗрд╖ рджреЗрд╢ рдХреЗ рд▓рд┐рдП рд╕реВрдЪрдирд╛ рдХреЗ рд╕реНрд░реЛрдд countryред

рд╣рдореЗрдВ рдЬрд┐рд╕ рд╡рд┐рдХрд▓реНрдк рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реЛрддреА рд╣реИ, рдЙрд╕рдХреЗ рдЖрд░рдВрдн рдХреЛ рд╕реБрд╡рд┐рдзрд╛рдЬрдирдХ рдмрдирд╛рдиреЗ рдХреЗ рд▓рд┐рдП, рд╣рдо рдЕрдиреБрдХреНрд░рдордгрд┐рдХрд╛ рдФрд░ рд╕реНрдЯреНрд░рд┐рдВрдЧ рдХреЗ рдЖрдзрд╛рд░ рдкрд░ рд▓реЗрдЦреЛрдВ рдФрд░ рд╕реВрдЪрдирд╛ рд╕реНрд░реЛрддреЛрдВ рдХреА рд╡рд┐рднрд┐рдиреНрди рд╕реВрдЪрд┐рдпреЛрдВ рдХреЗ рд▓рд┐рдП рдЧрдгрдирд╛ EndpointрдХрд░рдиреЗ рдХреЗ init?рд▓рд┐рдП рдПрдХ рдЗрдирд┐рд▓рд╛рдЗрдЬрд╝рд░ рдЬреЛрдбрд╝рддреЗ рд╣реИрдВ , рдЬрд┐рд╕рдореЗрдВ рд╡рд┐рднрд┐рдиреНрди рдЧрдгрдирд╛ рд╡рд┐рдХрд▓реНрдкреЛрдВ рдХреЗ рд▓рд┐рдП рдЕрд▓рдЧ-рдЕрд▓рдЧ рдЕрд░реНрде рд╣реЛрддреЗ рд╣реИрдВ:index  text

init? (index: Int, text: String = "sports") {
        switch index {
        case 0: self = .topHeadLines
        case 1: self = .search(searchFilter: text)
        case 2: self = .articlesFromCategory(text)
        case 3: self = .articlesFromSource(text)
        case 4: self = .sources (country: text)
        default: return nil
        }
    }

рдЖрдЗрдП рдХрдХреНрд╖рд╛ рдореЗрдВ рд╡рд╛рдкрд╕ рдЬрд╛рдПрдВ NewsAPI рдФрд░ рдкрд╣рд▓реЗ рддрд░реАрдХреЗ рдкрд░ рдЕрдзрд┐рдХ рд╡рд┐рд╕реНрддрд╛рд░ рд╕реЗ рд╡рд┐рдЪрд╛рд░ рдХрд░реЗрдВ  fetchArticles (from endpoint: Endpoint)-> AnyPublisher<[Article], Never>, рдЬреЛ [Article]рдкреИрд░рд╛рдореАрдЯрд░ рдХреЗ рдЖрдзрд╛рд░ рдкрд░ рд▓реЗрдЦреЛрдВ рдХрд╛ рдЪрдпрди endpointрдХрд░рддрд╛ рд╣реИ рдФрд░ рдХреЛрдИ рддреНрд░реБрдЯрд┐ рдирд╣реАрдВ рд▓реМрдЯрд╛рддрд╛ рд╣реИ Never: -

func fetchArticles(from endpoint: Endpoint) -> AnyPublisher<[Article], Never> {
        guard let url = endpoint.absoluteURL else {              // 0
                    return Just([Article]()).eraseToAnyPublisher()
        }
           return
            URLSession.shared.dataTaskPublisher(for:url)        // 1
            .map{$0.data}                                       // 2
            .decode(type: NewsResponse.self,                    // 3
                    decoder: APIConstants .jsonDecoder)
            .map{$0.articles}                                   // 4
            .replaceError(with: [])                             // 5
            .receive(on: RunLoop.main)                          // 6
            .eraseToAnyPublisher()                              // 7
    }

  • рд▓реЗрдЦреЛрдВ рдХреА рд╡рд╛рдВрдЫрд┐рдд рд╕реВрдЪреА рдХреЗ рдЕрдиреБрд░реЛрдз рдХреЗ рд▓рд┐рдП endpoint рдлреЙрд░реНрдо рдХреЗ рдЖрдзрд╛рд░ рдкрд░ , рдпрджрд┐ рдРрд╕рд╛ рдирд╣реАрдВ рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ, рддреЛ рд▓реЗрдЦреЛрдВ рдХреА рдПрдХ рдЦрд╛рд▓реА рд╕рд░рдгреА рд▓реМрдЯрд╛рдПрдВURLendpoint.absoluteURL[Article]()
  • ┬л┬╗ dataTaskPublisher(for:), Output (data: Data, response: URLResponse),   Failure - URLError,
  • map { } (data: Data, response: URLResponse)  data
  • JSON  data ,  NewsResponse, articles: [Atricle]
  • map { } articles
  • - [ ],
  • main , UI,
  • ┬л┬╗ ┬л┬╗ eraseToAnyPublisher() AnyPublisher.

рд╕реВрдЪрдирд╛ рд╕реНрд░реЛрддреЛрдВ рдХрд╛ рдЪрдпрди рдХрд░рдиреЗ рдХрд╛ рдХрд╛рд░реНрдп рджреВрд╕рд░реА рд╡рд┐рдзрд┐ рдХреЛ рд╕реМрдВрдкрд╛ рдЧрдпрд╛ рд╣реИ - fetchSources (for country: String) -> AnyPublisher<[Source], Never>рдЬреЛ рдкрд╣рд▓реА рд╡рд┐рдзрд┐ рдХреА рдПрдХ рд╕рдЯреАрдХ рд╢рдмреНрджрд╛рд░реНрде рдкреНрд░рддрд┐ рд╣реИ, рд╕рд┐рд╡рд╛рдп рдЗрд╕рдХреЗ рдХрд┐ рдЗрд╕ рдмрд╛рд░ рд▓реЗрдЦреЛрдВ рдХреЗ рдмрдЬрд╛рдп [Article]рд╣рдо рд╕реВрдЪрдирд╛ рд╕реНрд░реЛрддреЛрдВ рдХрд╛ рдЪрдпрди рдХрд░реЗрдВрдЧреЗ [Source]:

func fetchSources() -> AnyPublisher<[Source], Never> {
        guard let url = Endpoint.sources.absoluteURL else {      // 0
                       return Just([Source]()).eraseToAnyPublisher()
           }
              return
               URLSession.shared.dataTaskPublisher(for:url)      // 1
               .map{$0.data}                                     // 2
               .decode(type: SourcesResponse.self,               // 3
                       decoder: APIConstants .jsonDecoder)
               .map{$0.sources}                                  // 4
               .replaceError(with: [])                           // 5
               .receive(on: RunLoop.main)                        // 6
               .eraseToAnyPublisher()                            // 7
    }

рдпрд╣ AnyPublisher <[Source], Never>рд╕реВрдЪрдирд╛ рд╕реНрд░реЛрддреЛрдВ рдХреА рдПрдХ рд╕рд░рдгреА рдХреЗ рд░реВрдк рдореЗрдВ [Source] рдФрд░ рддреНрд░реБрдЯрд┐ рдХреА рдЕрдиреБрдкрд╕реНрдерд┐рддрд┐  Never (рддреНрд░реБрдЯрд┐рдпреЛрдВ рдХреЗ рдорд╛рдорд▓реЗ рдореЗрдВ, рд╕реВрддреНрд░реЛрдВ рдХрд╛ рдПрдХ рдЦрд╛рд▓реА рд╕рд░рдгреА рд▓реМрдЯрд╛рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ  [ ]) рдХреЗ рд░реВрдк рдореЗрдВ рдПрдХ рдореВрд▓реНрдп рдХреЗ рд╕рд╛рде "рдкреНрд░рдХрд╛рд╢рдХ" рд╣рдорд╛рд░реЗ рдкрд╛рд╕ рд▓реМрдЯрддрд╛ рд╣реИ ред

рд╣рдо рдЗрди рджреЛрдиреЛрдВ рд╡рд┐рдзрд┐рдпреЛрдВ рдХреЗ рд╕рд╛рдорд╛рдиреНрдп рднрд╛рдЧ рдХреЛ рд╕рд┐рдВрдЧрд▓ рдХрд░ рджреЗрдВрдЧреЗ, рдЗрд╕реЗ рдПрдХ GenericрдлрдВрдХреНрд╢рди рдХреЗ рд░реВрдк рдореЗрдВ рд╡реНрдпрд╡рд╕реНрдерд┐рдд рдХрд░реЗрдВрдЧреЗ, fetch(_ url: URL) -> AnyPublisher<T, Error>рдЬреЛ  Generic"рдкреНрд░рдХрд╛рд╢рдХ" AnyPublisher<T, Error>рдкрд░ рдЖрдзрд╛рд░рд┐рдд рд╣реИ URL:

//     URL
     func fetch<T: Decodable>(_ url: URL) -> AnyPublisher<T, Error> {
                   URLSession.shared.dataTaskPublisher(for: url)             // 1
                    .map { $0.data}                                          // 2
                    .decode(type: T.self, decoder: APIConstants.jsonDecoder) // 3
                    .receive(on: RunLoop.main)                               // 4
                    .eraseToAnyPublisher()                                   // 5
    }

рдпрд╣ рдкрд┐рдЫрд▓реЗ рджреЛ рддрд░реАрдХреЛрдВ рдХреЛ рд╕рд░рд▓ рдХрд░реЗрдЧрд╛:

//   
     func fetchArticles(from endpoint: Endpoint)
                                     -> AnyPublisher<[Article], Never> {
         guard let url = endpoint.absoluteURL else {
                     return Just([Article]()).eraseToAnyPublisher() // 0
         }
         return fetch(url)                                          // 1
             .map { (response: NewsResponse) -> [Article] in        // 2
                             return response.articles }
                .replaceError(with: [Article]())                    // 3
                .eraseToAnyPublisher()                              // 4
     }
    
    //    
    func fetchSources(for country: String)
                                       -> AnyPublisher<[Source], Never> {
        guard let url = Endpoint.sources(country: country).absoluteURL
            else {
                    return Just([Source]()).eraseToAnyPublisher() // 0
        }
        return fetch(url)                                         // 1
            .map { (response: SourcesResponse) -> [Source] in     // 2
                            response.sources }
               .replaceError(with: [Source]())                    // 3
               .eraseToAnyPublisher()                             // 4
    }

рдЗрд╕ рдкреНрд░рдХрд╛рд░ рдкреНрд░рд╛рдкреНрдд "рдкреНрд░рдХрд╛рд╢рдХ" рддрдм рддрдХ рдХреБрдЫ рдирд╣реАрдВ рджреЗрддреЗ рдЬрдм рддрдХ рдХрд┐ рдХреЛрдИ рд╡реНрдпрдХреНрддрд┐ рдЙрдирдХреА "рд╕рджрд╕реНрдпрддрд╛" рди рд▓реЗ рд▓реЗред рд╣рдо рдпрд╣ рддрдм рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ рдЬрдм рдбрд┐рдЬрд╛рдЗрдирд┐рдВрдЧ UIред

"рдкреНрд░рдХрд╛рд╢рдХ" PublisherрдХреЗ рд░реВрдк рдореЗрдВ View Model рдореЗрдВ SwiftUIред рд▓реЗрдЦреЛрдВ рдХреА рд╕реВрдЪреАред


рдЕрдм рдХрд╛рдордХрд╛рдЬ рдХреЗ рддрд░реНрдХ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдереЛрдбрд╝рд╛ SwiftUIред  "рдмрд╛рд╣рд░реА рдкрд░рд┐рд╡рд░реНрддрдиреЛрдВ"

рдХрд╛ SwiftUIрдПрдХрдорд╛рддреНрд░ рдЕрдореВрд░реНрдд рд╣реИ, рдЬрд┐рд╕рдХрд╛ рд╡реЗ рдЬрд╡рд╛рдм рджреЗрддреЗ рд╣реИрдВ View"рдкреНрд░рдХрд╛рд╢рдХ" Publisherред "рдмрд╛рд╣рд░реА рдкрд░рд┐рд╡рд░реНрддрди" рдХреЛ рдПрдХ рдЯрд╛рдЗрдорд░ Timer, рдЕрдзрд┐рд╕реВрдЪрдирд╛ NotificationCenter рдпрд╛ рдЖрдкрдХреЗ рдореЙрдбрд▓ рдСрдмреНрдЬреЗрдХреНрдЯ рдХреЗ рд╕рд╛рде рд╕рдордЭрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ , рдЬреЛ рдкреНрд░реЛрдЯреЛрдХреЙрд▓ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ ObservableObjectрдПрдХ рдмрд╛рд╣рд░реА рдПрдХрд▓ "рд╕рддреНрдп рдХрд╛ рд╕реНрд░реЛрдд" (рд╕рдЪреНрдЪрд╛рдИ рдХрд╛ рд╕реНрд░реЛрдд) рдореЗрдВ рдмрджрд▓ рд╕рдХрддрд╛ рд╣реИред 

рд╕рд╛рдорд╛рдиреНрдп "рдкреНрд░рдХрд╛рд╢рдХ" рдкреНрд░рдХрд╛рд░ Timerрдпрд╛ NotificationCenter Viewрд╡рд┐рдзрд┐ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛ рдХрд░рддрд╛ рд╣реИ onReceive (_: perform:)ред "рдкреНрд░рдХрд╛рд╢рдХ" рдХреЗ рдЙрдкрдпреЛрдЧ рдХрд╛ рдПрдХ рдЙрджрд╛рд╣рд░рдг Timerрд╣рдо рд╣реИрдХрд░ рд╕рдорд╛рдЪрд╛рд░ рдХреЗ рд▓рд┐рдП рдПрдХ рдЖрд╡реЗрджрди рдХреЗ рдирд┐рд░реНрдорд╛рдг рдкрд░ рддреАрд╕рд░реЗ рд▓реЗрдЦ рдореЗрдВ рдмрд╛рдж рдореЗрдВ рдкреЗрд╢ рдХрд░реЗрдВрдЧреЗ ред

рдЗрд╕ рд▓реЗрдЦ рдореЗрдВ, рд╣рдо рдЗрд╕ рдмрд╛рдд рдкрд░ рдзреНрдпрд╛рди рджреЗрдВрдЧреЗ рдХрд┐ рд╣рдорд╛рд░реЗ рдореЙрдбрд▓ рдХреЛ рдХреИрд╕реЗ рдмрдирд╛рдпрд╛ рдЬрд╛рдП SwiftUIрдмрд╛рд╣реНрдп "рд╕рддреНрдп рдХрд╛ рд╕реНрд░реЛрдд" (рд╕рддреНрдп рдХрд╛ рд╕реНрд░реЛрдд)ред

рдЖрдЗрдП рдкрд╣рд▓реЗ рджреЗрдЦрддреЗ рд╣реИрдВ рдХрд┐ SwiftUIрд╡рд┐рднрд┐рдиреНрди рдкреНрд░рдХрд╛рд░ рдХреЗ рд▓реЗрдЦреЛрдВ рдХреЛ рдкреНрд░рджрд░реНрд╢рд┐рдд рдХрд░рдиреЗ рдХреЗ рдкрд░рд┐рдгрд╛рдорд╕реНрд╡рд░реВрдк "рдкреНрд░рдХрд╛рд╢рдХ" рдХреЛ рдХрд┐рд╕ рдкреНрд░рдХрд╛рд░ рдПрдХ рд╡рд┐рд╢рд┐рд╖реНрдЯ рдЙрджрд╛рд╣рд░рдг рдореЗрдВ рдХрд╛рд░реНрдп рдХрд░рдирд╛ рдЪрд╛рд╣рд┐рдП:

.topHeadLines- рдирд╡реАрдирддрдо рд╕рдорд╛рдЪрд╛рд░,  .articlesFromCategory(_ category: String) - рдПрдХ рд╡рд┐рд╢рд┐рд╖реНрдЯ рд╢реНрд░реЗрдгреА рдХреЗ  .articlesFromSource(_ source: String) рд▓рд┐рдП рд╕рдорд╛рдЪрд╛рд░ , - рд╕реВрдЪрдирд╛ рдХреЗ рдПрдХ рд╡рд┐рд╢рд┐рд╖реНрдЯ рд╕реНрд░реЛрдд рдХреЗ рд▓рд┐рдП рд╕рдорд╛рдЪрд╛рд░, .search (searchFilter: String) - рдПрдХ рдирд┐рд╢реНрдЪрд┐рдд рд╕реНрдерд┐рддрд┐ рджреНрд╡рд╛рд░рд╛ рдЪрдпрдирд┐рдд рд╕рдорд╛рдЪрд╛рд░ред рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛



рдХрд┐рд╕ рдЖрдзрд╛рд░ рдкрд░ EndpointрдЪреБрдирд╛рд╡ рдХрд░рддрд╛ рд╣реИ, рдЗрд╕рдХреЗ рдЖрдзрд╛рд░ рдкрд░ рд╣рдореЗрдВ NewsAPI.orgarticles рд╕реЗ рдЪреБрдиреЗ рдЧрдП рд▓реЗрдЦреЛрдВ рдХреА рд╕реВрдЪреА рдХреЛ рдЕрдкрдбреЗрдЯ рдХрд░рдирд╛ рд╣реЛрдЧрд╛ ред рдРрд╕рд╛ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рд╣рдо рдПрдХ рдмрд╣реБрдд рд╣реА рд╕рд░рд▓ рд╡рд░реНрдЧ рдмрдирд╛рдПрдВрдЧреЗ рдЬреЛ  рддреАрди рдЧреБрдгреЛрдВ рд╡рд╛рд▓реЗ  ArticlesViewModelрдПрдХ рдкреНрд░реЛрдЯреЛрдХреЙрд▓ ObservableObjectрдХреЛ  рд▓рд╛рдЧреВ рдХрд░рддрд╛ рд╣реИ @Published:
 


  • @Published var indexEndpoint: Int тАФ Endpoint ( ┬л┬╗, View),  
  • @Published var searchString: String тАФ ,   ( ┬л┬╗, View  TextField),
  • @Published var articles: [Article] - ( ┬л┬╗, NewsAPI.org, ┬л┬╗).

рдЬреИрд╕реЗ рд╣реА рд╣рдо рд╕реЗрдЯ рдХреЗ рд░реВрдк рдореЗрдВ  @Published рдЧреБрдг indexEndpoint рдпрд╛ searchString, рд╣рдо рдЙрди рджреЛрдиреЛрдВ рдХреЛ рд╕рд░рд▓ рдЧреБрдг рдХреЗ рд░реВрдк рдореЗрдВ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рд╢реБрд░реВ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ  indexEndpoint рдФрд░  searchString, рдФрд░ "рдкреНрд░рдХрд╛рд╢рдХреЛрдВ" рдХреЗ рд░реВрдк рдореЗрдВ  $indexEndpointрдФрд░  $searchStringред

рдПрдХ рд╡рд░реНрдЧ рдореЗрдВ  ArticlesViewModel, рдЖрдк рди рдХреЗрд╡рд▓ рд╣рдорд╛рд░реЗ рд▓рд┐рдП рд╣рд┐рдд рдХреЗ рдЧреБрдгреЛрдВ рдХреА рдШреЛрд╖рдгрд╛ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ, рдмрд▓реНрдХрд┐ рдЙрдирдХреЗ рдЗрдВрдЯрд░реИрдХреНрд╢рди рдХреЗ рд╡реНрдпрд╛рдкрд╛рд░рд┐рдХ рддрд░реНрдХ рднреА рд▓рд┐рдЦ рд╕рдХрддреЗ рд╣реИрдВред рдпрд╣ рдЕрдВрдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рдЬрдм рдХрд┐рд╕реА рд╡рд░реНрдЧ рдХреЗ рдЙрджрд╛рд╣рд░рдг рдХреЛ рдкреНрд░рд╛рд░рдВрднрд┐рдХ рд░реВрдк рд╕реЗ рджреЗрдЦрддреЗ ArticlesViewModel рд╣реБрдП, initрд╣рдо рдПрдХ "рд╕рджрд╕реНрдпрддрд╛" рдмрдирд╛ рд╕рдХрддреЗ рд╣реИрдВ рдЬреЛ рдХрдХреНрд╖рд╛ рдХреЗ рдЙрджрд╛рд╣рд░рдг рдХреЗ  рдкреВрд░реЗ "рдЬреАрд╡рди рдЪрдХреНрд░" рдкрд░ рдХрд╛рд░реНрдп рдХрд░реЗрдЧрд╛   рдФрд░ рд╕реВрдЪрдХрд╛рдВрдХ рдФрд░ рдЦреЛрдЬ рд╕реНрдЯреНрд░рд┐рдВрдЧ рдкрд░  ArticlesViewModelрд▓реЗрдЦреЛрдВ рдХреА рд╕реВрдЪреА рдХреА рдирд┐рд░реНрднрд░рддрд╛ рдХреЛ рдкреБрди: рдЙрддреНрдкрдиреНрди рдХрд░реЗрдЧрд╛ ред рдРрд╕рд╛ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рд╣рдо "рдкреНрд░рдХрд╛рд╢рдХреЛрдВ" рдХреА рд╢реНрд░реГрдВрдЦрд▓рд╛ рдХрд╛ рд╡рд┐рд╕реНрддрд╛рд░  рдФрд░ рдЙрддреНрдкрд╛рджрди "рдкреНрд░рдХрд╛рд╢рдХ" рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдПarticlesindexEndpointsearchString

Combine$indexEndpoint$searchStringAnyPublisher<[Article], Never>рдЬрд┐рд╕рдХрд╛ рдорд╛рди рд▓реЗрдЦреЛрдВ рдХреА рдПрдХ рд╕реВрдЪреА рд╣реИ  articlesред рдлрд┐рд░ рд╣рдо рдСрдкрд░реЗрдЯрд░ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдЗрд╕реЗ "рд╕рдмреНрд╕рдХреНрд░рд╛рдЗрдм" рдХрд░рддреЗ рд╣реИрдВ assign (to: \.articles, on: self)рдФрд░ рдЙрди рд▓реЗрдЦреЛрдВ рдХреА рд╕реВрдЪреА рдкреНрд░рд╛рдкреНрдд рдХрд░рддреЗ рд╣реИрдВ рдЬрд┐рдирдХреА рд╣рдореЗрдВ articles "рдЖрдЙрдЯрдкреБрдЯ" @Published рд╕рдВрдкрддреНрддрд┐ рдХреЗ рд░реВрдк рдореЗрдВ  рдЬрд╝рд░реВрд░рдд рд╣реЛрддреА рд╣реИ рдЬреЛ рдкрд░рд┐рднрд╛рд╖рд┐рдд рдХрд░рддрд╛ рд╣реИ UIред

рд╣рдо рдЧреБрдгреЛрдВ рд╕реЗ рдирд╣реАрдВ рдмрд╕ рд╢реНрд░реГрдВрдЦрд▓рд╛ рдЦреАрдВрдЪ рдЪрд╛рд╣рд┐рдП  indexEndpointрдФрд░ searchStringрдЕрд░реНрдерд╛рддреН "рдкреНрд░рдХрд╛рд╢рдХреЛрдВ" рд╕реЗ, $indexEndpointрдФрд░ $searchStringрдЬреЛ рдирд┐рд░реНрдорд╛рдг рдореЗрдВ рднрд╛рдЧ рд▓реЗрдиреЗ UIрдХреА рдорджрдж рд╕реЗ SwiftUIрдФрд░ рд╣рдо рдЙрдиреНрд╣реЗрдВ рд╡рд╣рд╛рдБ рдмрджрд▓рдиреЗ рдХреЗ рдпреВрдЬрд░ рдЗрдВрдЯрд░рдлреЗрд╕ рддрддреНрд╡реЛрдВ рдХрд╛ рдЙрдкрдпреЛрдЧ рд╣реЛрдЧрд╛  PickerрдФрд░ TextFieldред

рд╣рдо рдпрд╣ рдХреИрд╕реЗ рдХрд░реЗрдВрдЧреЗ?

рд╣рдорд╛рд░реЗ рдкрд╛рд╕ рдкрд╣рд▓реЗ рд╕реЗ рд╣реА рд╣рдорд╛рд░реЗ рд╢рд╕реНрддреНрд░рд╛рдЧрд╛рд░ рдореЗрдВ рдПрдХ рдлрд╝рдВрдХреНрд╢рди fetchArticles (from: Endpoint)рд╣реИ рдЬреЛ рдХрдХреНрд╖рд╛ рдореЗрдВ рд╣реИ  NewsAPIрдФрд░ AnyPublisher<[Article], Never>рдореВрд▓реНрдп рдХреЗ рдЖрдзрд╛рд░ рдкрд░ рдПрдХ "рдкреНрд░рдХрд╛рд╢рдХ" рджреЗрддрд╛ рд╣реИEndpoint, рдФрд░ рд╣рдо рдХреЗрд╡рд▓ "рдкреНрд░рдХрд╛рд╢рдХреЛрдВ" рдХреЗ рдореВрд▓реНрдпреЛрдВ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ  $indexEndpointрдФрд░  $searchStringрдЙрдиреНрд╣реЗрдВ endpointрдЗрд╕ рдлрд╝рдВрдХреНрд╢рди рдХреЗ рддрд░реНрдХ рдореЗрдВ рдмрджрд▓ рд╕рдХрддреЗ рд╣реИрдВ ред 

рд╕рдмрд╕реЗ рдкрд╣рд▓реЗ, "рдкреНрд░рдХрд╛рд╢рдХреЛрдВ" рдХреЛ рдорд┐рд▓рд╛рдПрдВ  $indexEndpoint рдФрд░  $searchStringред рдЗрд╕рдХреЗ рд▓рд┐рдП, CombineрдСрдкрд░реЗрдЯрд░ рдореМрдЬреВрдж рд╣реИ Publishers.CombineLatest :



рдкрд┐рдЫрд▓реЗ "рдкреНрд░рдХрд╛рд╢рдХ" рд╕реЗ рдкреНрд░рд╛рдкреНрдд рдЖрдВрдХрдбрд╝реЛрдВ рдХреЗ рдЖрдзрд╛рд░ рдкрд░ рдПрдХ рдирдпрд╛ "рдкреНрд░рдХрд╛рд╢рдХ" рдмрдирд╛рдиреЗ рдХреЗ рд▓рд┐рдП Combine , рдСрдкрд░реЗрдЯрд░ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ  flatMap:



рдЕрдЧрд▓рд╛, рд╣рдо рдПрдХ рдмрд╣реБрдд рд╣реА рд╕рд░рд▓ "рдЧреНрд░рд╛рд╣рдХ" рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдЗрд╕ рдирдП рдкреНрд░рд╛рдкреНрдд "рдкреНрд░рдХрд╛рд╢рдХ" рдХреА "рд╕рджрд╕реНрдпрддрд╛ рд▓реЗрддреЗ рд╣реИрдВ"  assign (to: \.articles, on: self)рдФрд░ "рд╕реЗ рдкреНрд░рд╛рдкреНрдд" рдЕрд╕рд╛рдЗрди рдХрд░рддреЗ рд╣реИрдВред рдкреНрд░рдХрд╛рд╢рдХ " @Published рд╕рд░рдгреА рдХреЗ  рд▓рд┐рдП рдореВрд▓реНрдп  articles:



рд╣рдордиреЗ рд╕рд┐рд░реНрдл рдПрдХ init( )ASYNCHRONOUS" рдкреНрд░рдХрд╛рд╢рдХ "рдмрдирд╛рдпрд╛ рдФрд░ рдЗрд╕рдХреЗ рдкрд░рд┐рдгрд╛рдорд╕реНрд╡рд░реВрдк" рд╕рджрд╕реНрдпрддрд╛ рд▓рд┐рдпрд╛ "AnyCancellable"рд╕рджрд╕реНрдпрддрд╛" рдФрд░ рдпрд╣ рд╕рддреНрдпрд╛рдкрд┐рдд рдХрд░рдирд╛ рдЖрд╕рд╛рди рд╣реИ рдХрд┐ рдХреНрдпрд╛ рд╣рдо рдЕрдкрдиреА "рд╕рджрд╕реНрдпрддрд╛" рдХреЛ рд╕реНрдерд┐рд░ рд░рдЦрддреЗ рд╣реИрдВ let subscription: "рд╕рджрд╕реНрдпрддрд╛"



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

рдЗрд╕ рддрд░рд╣ рдХреЗ "рд╕рдмреНрд╕рдХреНрд░рд┐рдкреНрд╢рди" рдХреЛ рдмрдЪрд╛рдиреЗ рдХреЗ рд▓рд┐рдП, рдЗрдирд┐рд╢рд┐рдпрд▓рд╛рдЗрдЬрд╝рд░ рд╕реЗ рдкрд╣рд▓реЗ рдПрдХ init() рд╡реИрд░рд┐рдПрдмрд▓ рдмрдирд╛рдирд╛ рдЖрд╡рд╢реНрдпрдХ рд╣реИ, рдЬреЛ рдЗрд╕ "рд╡реИрд░рд┐рдПрдмрд▓" рдХреЛ рдЗрд╕ "рд╡реИрд░рд┐рдПрдмрд▓" рдХреЛ рдХреНрд▓рд╛рд╕ рдЙрджрд╛рд╣рд░рдг рдХреЗ рдкреВрд░реЗ "рд▓рд╛рдЗрдл рд╕рд╛рдЗрдХрд▓" рдореЗрдВ  var cancellableSetрд╕реЗрд╡ рдХрд░реЗрдЧрд╛  ред AnyCancellableArticlesViewMode

рдЗрд╕рд▓рд┐рдП, рд╣рдо рдирд┐рд░рдВрддрд░ рдХреЛ рд╣рдЯрд╛рддреЗ рд╣реИрдВ let subscriptionрдФрд░ рдСрдкрд░реЗрдЯрд░ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ AnyCancellableрдЪрд░ рдореЗрдВ рд╣рдорд╛рд░реЗ "рд╕рдмреНрд╕рдХреНрд░рд┐рдкреНрд╢рди" рдХреЛ  рдпрд╛рдж cancellableSetрдХрд░рддреЗ рд╣реИрдВ .store ( in: &self.cancellableSet):



ASYNCHRONOUS "рдкреНрд░рдХрд╛рд╢рдХ" рдХреЗ рд▓рд┐рдП "рд╕рдмреНрд╕рдХреНрд░рд┐рдкреНрд╢рди" рдЬреЛ рд╣рдордиреЗ рдмрдирд╛рдпрд╛ init( )рд╣реИ рд╡рд╣ рдХрдХреНрд╖рд╛ рдЙрджрд╛рд╣рд░рдг рдХреЗ рдкреВрд░реЗ "рдЬреАрд╡рди рдЪрдХреНрд░" рдореЗрдВ рд╕рдВрд░рдХреНрд╖рд┐рдд рд░рд╣реЗрдЧрд╛  ArticlesViewModelред

рд╣рдо рдордирдорд╛рдиреЗ рдврдВрдЧ рд╕реЗ "рдкреНрд░рдХрд╛рд╢рдХреЛрдВ" $indexEndpointрдФрд░ / рдпрд╛  рдХрд╛ рдЕрд░реНрде рдмрджрд▓ рд╕рдХрддреЗ рд╣реИрдВ  searchString, рдФрд░ рд╣рдореЗрд╢рд╛ рдмрдирд╛рдП рдЧрдП "рд╕рджрд╕реНрдпрддрд╛" рдХреЗ рд▓рд┐рдП рдзрдиреНрдпрд╡рд╛рдж, рд╣рдорд╛рд░реЗ рдкрд╛рд╕ articlesрдмрд┐рдирд╛ рдХрд┐рд╕реА рдЕрддрд┐рд░рд┐рдХреНрдд рдкреНрд░рдпрд╛рд╕ рдХреЗ рдЗрди рджреЛ рдкреНрд░рдХрд╛рд╢рдХреЛрдВ рдХреЗ рдореВрд▓реНрдпреЛрдВ рдХреЗ рдЕрдиреБрд░реВрдк рд▓реЗрдЦреЛрдВ рдХреА рдПрдХ рд╕рд░рдгреА рд╣реЛрдЧреА  ред рдЗрд╕  ObservableObjectрд╡рд░реНрдЧ рдХреЛ рдЖрдорддреМрд░ рдкрд░ рдХрд╣рд╛ рдЬрд╛рддрд╛ рд╣реИ  View Modelред

рдЦреЛрдЬ рд╕реНрдЯреНрд░рд┐рдВрдЧ рдЯрд╛рдЗрдк рдХрд░рддреЗ рд╕рдордп рд╕рд░реНрд╡рд░ рдкрд░ рдХреЙрд▓ рдХреА рд╕рдВрдЦреНрдпрд╛ рдХрдо рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП searchString, рд╣рдореЗрдВ рдЦреЛрдЬ рд╕реНрдЯреНрд░рд┐рдВрдЧ рдХреЗ "рдкреНрд░рдХрд╛рд╢рдХ" рдХрд╛ рдЙрдкрдпреЛрдЧ рдирд╣реАрдВ рдХрд░рдирд╛ рдЪрд╛рд╣рд┐рдП $searchString, рдФрд░ рдЗрд╕рдХрд╛ рд╕рдВрд╢реЛрдзрд┐рдд рд╕рдВрд╕реНрдХрд░рдг validString:



рдЕрдм рдЬрдм рд╣рдорд╛рд░реЗ рдкрд╛рд╕ View Modelрд╣рдорд╛рд░реЗ рд▓реЗрдЦ рд╣реИрдВ, рддреЛ рд╣рдо рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдЗрдВрдЯрд░рдлрд╝реЗрд╕ ( UI) рдмрдирд╛рдирд╛ рд╢реБрд░реВ рдХрд░рддреЗ рд╣реИрдВ ред рдореЗрдВ SwiftUIрд╕рд┐рдВрдХреНрд░рдирд╛рдЗрдЬрд╝ рдХрд░рдиреЗ рдХреЗ Viewрд╕рд╛рде ObservableObject рдореЙрдбрд▓, рдПрдХ @ObservedObjectрдЪрд░ рд░рд╣рд╛ рд╣реИ рдкреНрд░рдпреЛрдЧ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ рдХрд┐ рдЗрд╕ рдореЙрдбрд▓ рдХреЗ рд╡рд░реНрдЧ рдХрд╛ рдПрдХ рдЙрджрд╛рд╣рд░рдг рдХреЛ рджрд░реНрд╢рд╛рддрд╛ рд╣реИред рдпрд╣ рдЬреЛрдбрд╝реА рд╣реИ -  ObservableObject рд╡рд░реНрдЧ рдФрд░  @ObservedObjectрдЪрд░ рдЬреЛ рдЗрд╕ рд╡рд░реНрдЧ рдХреЗ рдЙрджрд╛рд╣рд░рдг рдХреЛ рд╕рдВрджрд░реНрднрд┐рдд рдХрд░рддрд╛ рд╣реИ - рдЬреЛ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдЗрдВрдЯрд░рдлрд╝реЗрд╕ ( UI) рдореЗрдВ рдкрд░рд┐рд╡рд░реНрддрди рдХреЛ рдирд┐рдпрдВрддреНрд░рд┐рдд рдХрд░рддрд╛ рд╣реИ  SwiftUIред

рд╣рдо рдПрдХ рдЪрд░ рдХреЗ рд░реВрдк рдореЗрдВ ContentView рд╡рд░реНрдЧ рдХреЗ рдПрдХ рдЙрджрд╛рд╣рд░рдг рдХреЛ рд╕рдВрд░рдЪрдирд╛ рдореЗрдВ рдЬреЛрдбрд╝рддреЗ рд╣реИрдВ рдФрд░ рдЗрд╕реЗ рд▓реЗрдЦреЛрдВ рдХреА рдПрдХ рд╕реВрдЪреА рдХреЗ рд╕рд╛рде рдкреНрд░рддрд┐рд╕реНрдерд╛рдкрд┐рдд рдХрд░рддреЗ рд╣реИрдВ рдЬрд┐рд╕рдореЗрдВ рд╣рдо рдЕрдкрдиреЗ рд▓реЗрдЦреЛрдВ рдХреЗ рд▓рд┐рдП рдкреНрд░рд╛рдкреНрдд рд▓реЗрдЦреЛрдВ  рдХреЛ рд░рдЦрддреЗ рд╣реИрдВ ArticleViewModel var articleViewModelText ("Hello, World!")ArticlesListarticlesViewModel.articlesView Modelред рдирддреАрдЬрддрди, рд╣рдореЗрдВ рдПрдХ рдирд┐рд╢реНрдЪрд┐рдд рдФрд░ рдбрд┐рдлрд╝реЙрд▓реНрдЯ рд╕реВрдЪрдХрд╛рдВрдХ рдХреЗ рд▓рд┐рдП рд▓реЗрдЦреЛрдВ рдХреА рдПрдХ рд╕реВрдЪреА рдорд┐рд▓рддреА рд╣реИ  indexEndpoint = 0, рдЬреЛ рдХрд┐ .topHeadLines рдирд╡реАрдирддрдо рд╕рдорд╛рдЪрд╛рд░реЛрдВ рдХреЗ рд▓рд┐рдП рд╣реИ:



рд╣рдорд╛рд░реЗ рд╕реНрдХреНрд░реАрди UIрдкрд░ рдПрдХ рддрддреНрд╡ рдЬреЛрдбрд╝реЗрдВ  рдЬреЛ рд▓реЗрдЦреЛрдВ рдХреЗ рд╕реЗрдЯ рдХреЛ рдкреНрд░рджрд░реНрд╢рд┐рдд рдХрд░рдирд╛ рдЪрд╛рд╣рддреЗ рд╣реИрдВред рд╣рдо Pickerрд╕реВрдЪрдХрд╛рдВрдХ рдкрд░рд┐рд╡рд░реНрддрди рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░реЗрдВрдЧреЗ  $articlesViewModel.indexEndpointред рдПрдХ рдкреНрд░рддреАрдХ рдХреА рдЙрдкрд╕реНрдерд┐рддрд┐  $рдЕрдирд┐рд╡рд╛рд░реНрдп рд╣реИ, рдХреНрдпреЛрдВрдХрд┐ рдЗрд╕рдХрд╛ рдорддрд▓рдм @Published "рдкреНрд░рдХрд╛рд╢рдХ" рджреНрд╡рд╛рд░рд╛ рдЖрдкреВрд░реНрддрд┐ рдХрд┐рдП рдЧрдП рдореВрд▓реНрдп рдореЗрдВ рдмрджрд▓рд╛рд╡ рд╣реИ  ред рдЗрд╕ "рдкреНрд░рдХрд╛рд╢рдХ" рдХреЗ рд▓рд┐рдП "рд╕рджрд╕реНрдпрддрд╛" рддреБрд░рдВрдд рд╢реБрд░реВ рд╣реЛ рдЬрд╛рддреА рд╣реИ, рдЬрд┐рд╕ рдкрд░ рд╣рдордиреЗ рд╢реБрд░реБрдЖрдд рдХреА init (), "рдЖрдЙрдЯрдкреБрдЯ"  @Published"рдкреНрд░рдХрд╛рд╢рдХ"  articles рдмрджрд▓ рдЬрд╛рдПрдЧрд╛ рдФрд░ рд╣рдо рд╕реНрдХреНрд░реАрди рдкрд░ рд▓реЗрдЦреЛрдВ рдХреА рдПрдХ рдЕрд▓рдЧ рд╕реВрдЪреА рджреЗрдЦреЗрдВрдЧреЗ:



рдЗрд╕ рддрд░рд╣ рд╣рдо рддреАрди рд╡рд┐рдХрд▓реНрдкреЛрдВ рдХреЗ рд▓рд┐рдП рд▓реЗрдЦреЛрдВ рдХреЗ рд╕рд░рдгрд┐рдпреЛрдВ рдХреЛ рдкреНрд░рд╛рдкреНрдд рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ - "рдЯреЙрдкрд╣реЗрдбрд▓рд╛рдЗрди", "рдЦреЛрдЬ "рдФрд░" рд╢реНрд░реЗрдгреА рд╕реЗ ":



... рд▓реЗрдХрд┐рди рдПрдХ рдирд┐рд╢реНрдЪрд┐рдд рдФрд░ рдбрд┐рдлрд╝реЙрд▓реНрдЯ рдЦреЛрдЬ рд╕реНрдЯреНрд░рд┐рдВрдЧ рдХреЗ рд▓рд┐рдП searchString = "sports"(рдЬрд╣рд╛рдВ рдЗрд╕рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реЛрддреА рд╣реИ):



рд╣рд╛рд▓рд╛рдВрдХрд┐, рд╡рд┐рдХрд▓реНрдк рдХреЗ рд▓рд┐рдП,  "search" рдЖрдкрдХреЛ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ SearchViewрдХреЛ рдЦреЛрдЬ рд╕реНрдЯреНрд░рд┐рдВрдЧ рджрд░реНрдЬ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдПрдХ рдкрд╛рда рдлрд╝реАрд▓реНрдб рдкреНрд░рджрд╛рди рдХрд░рдирд╛ рд╣реЛрдЧрд╛ :



рдкрд░рд┐рдгрд╛рдорд╕реНрд╡рд░реВрдк, рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдЯрд╛рдЗрдк рдХрд┐рдП рдЧрдП рдЦреЛрдЬ рд╕реНрдЯреНрд░рд┐рдВрдЧ рджреНрд╡рд╛рд░рд╛ рдХрд┐рд╕реА рднреА рд╕рдорд╛рдЪрд╛рд░ рдХреЛ рдЦреЛрдЬ рд╕рдХрддрд╛ рд╣реИ:



рд╡рд┐рдХрд▓реНрдк рдХреЗ рд▓рд┐рдП,  "from category" рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдХреЛ рдкреНрд░рджрд╛рди рдХрд░рдирд╛ рдЖрд╡рд╢реНрдпрдХ рд╣реИ рдЕрд╡рд╕рд░ рдПрдХ рд╡рд░реНрдЧ рдХрд╛ рдЪрдпрди рдХрд░рдиреЗ рдФрд░ рд╣рдо рд╢реНрд░реЗрдгреА рдХреЗ рд╕рд╛рде рд╢реБрд░реВ science:



рдПрдХ рдкрд░рд┐рдгрд╛рдо рдХреЗ рд░реВрдк, рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдЦрдмрд░ рдХреЗ рдЪрдпрдирд┐рдд рд╢реНрд░реЗрдгреА рдкрд░ рдХрд┐рд╕реА рднреА рдЦрдмрд░ рдХреЗ рд▓рд┐рдП рдЦреЛрдЬ рд╕рдХрддреЗ рд╣реИрдВ - science, healthbusiness, technology:



рд╣рдо рджреЗрдЦ рд╕рдХрддреЗ рд╣реИрдВ рдХрд┐ рдПрдХ рдмрд╣реБрдд рд╣реА рд╕рд░рд▓  ObservableObject рдореЙрдбрд▓ рджреЛ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдирд┐рдпрдВрддреНрд░рд┐рдд рд╣реИ рдХрд┐ @Published рд╕реБрд╡рд┐рдзрд╛рдУрдВ - indexEndpoint рдФрд░searchString- рдЖрдк NewsAPI.org рд╡реЗрдмрд╕рд╛рдЗрдЯ рд╕реЗ рд╡рд┐рд╕реНрддреГрдд рдЬрд╛рдирдХрд╛рд░реА рдХрд╛ рдЪрдпрди рдХрд░рдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рджреЗрддрд╛ рд╣реИ  ред

рд╕реВрдЪрдирд╛ рдХреЗ рд╕реНрд░реЛрддреЛрдВ рдХреА рд╕реВрдЪреА


рдЖрдЗрдП SwiftUI рджреЗрдЦреЗрдВ рдХрд┐ NewsAPI рд╡рд░реНрдЧ рдореЗрдВ рдкреНрд░рд╛рдкреНрдд рд╕реВрдЪрдирд╛ рд╕реНрд░реЛрддреЛрдВ рдХрд╛ "рдкреНрд░рдХрд╛рд╢рдХ" рдХреИрд╕реЗ рдХрд╛рд░реНрдп рдХрд░реЗрдЧрд╛ fetchSources (for country: String) -> AnyPublisher<[Source], Never>ред

рд╣рдо рд╡рд┐рднрд┐рдиреНрди рджреЗрд╢реЛрдВ рдХреЗ рд▓рд┐рдП рдЬрд╛рдирдХрд╛рд░реА рдХреЗ рд╕реНрд░реЛрддреЛрдВ рдХреА рдПрдХ рд╕реВрдЪреА рдкреНрд░рд╛рдкреНрдд рдХрд░реЗрдВрдЧреЗ:



... рдФрд░ рдирд╛рдо рд╕реЗ рдЙрдирдХреЗ рд▓рд┐рдП рдЦреЛрдЬ рдХрд░рдиреЗ рдХреА рдХреНрд╖рдорддрд╛:



... рд╕рд╛рде рд╣реА рдЪрдпрдирд┐рдд рд╕реНрд░реЛрдд рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рд╡рд┐рд╕реНрддреГрдд рдЬрд╛рдирдХрд╛рд░реА: рдЗрд╕рдХрд╛ рдирд╛рдо, рд╢реНрд░реЗрдгреА, рджреЗрд╢, рд╕рдВрдХреНрд╖рд┐рдкреНрдд рд╡рд┐рд╡рд░рдг рдФрд░ рд╕рд╛рдЗрдЯ рдХрд╛ рд▓рд┐рдВрдХ: 



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

рдпрд╣ рд╕рдм рдХрд╛рдо рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рдЖрдкрдХреЛ рдПрдХ рдЕрддреНрдпрдВрдд рд╕рд░рд▓  ObservableObjectрдореЙрдбрд▓ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ рдЬрд┐рд╕рдореЗрдВ рдХреЗрд╡рд▓ рджреЛ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛-рдирд┐рдпрдВрддреНрд░рд┐рдд @PublishedрдЧреБрдг рд╣реИрдВ - searchString рдФрд░  country:



рдФрд░ рдлрд┐рд░, рд╣рдо рдПрдХ рд╣реА рдпреЛрдЬрдирд╛ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рд╣реИрдВ: рдЬрдм рдПрдХ рд╡рд░реНрдЧ рдХреЗ рд╡рд░реНрдЧ рдХреЗ рдПрдХ рдЙрджрд╛рд╣рд░рдг рдХреЛ рдкреНрд░рд╛рд░рдВрднрд┐рдХ рдХрд░рддреЗ SourcesViewModel рд╣реБрдП initрд╣рдо рдПрдХ "рд╕рдмрд╕реНрдХреНрд░рд┐рдкреНрд╢рди" рдмрдирд╛рддреЗ рд╣реИрдВ рдЬреЛ рдХрдХреНрд╖рд╛ рдЙрджрд╛рд╣рд░рдг рдХреЗ рдкреВрд░реЗ "рдЬреАрд╡рди рдЪрдХреНрд░" рдореЗрдВ рдХрд╛рдо рдХрд░реЗрдЧрд╛  SourcesViewModelрдФрд░ рдпрд╣ рд╕реБрдирд┐рд╢реНрдЪрд┐рдд рдХрд░реЗрдЧрд╛ рдХрд┐ рд╕реВрдЪрдирд╛ рд╕реНрд░реЛрддреЛрдВ рдХреА рд╕реВрдЪреА sourcesрджреЗрд╢ countryрдФрд░ рдЦреЛрдЬ рд╕реНрдЯреНрд░рд┐рдВрдЧ рдкрд░  рдирд┐рд░реНрднрд░ рдХрд░рддреА рд╣реИ   searchStringред

рдорджрдж рдХреЗ рд╕рд╛рде  Combineрд╣рдо "рдкреНрд░рдХрд╛рд╢рдХреЛрдВ" рд╕реЗ рдЪреЗрди рдЦреАрдВрдЪ $searchString рдФрд░ $countryрдЙрддреНрдкрд╛рджрди "рдкреНрд░рдХрд╛рд╢рдХ" рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП AnyPublisher<[Source], Never>, рдЬрд┐рд╕рдХрд╛ рдореВрд▓реНрдп рдЬрд╛рдирдХрд╛рд░реА рд╕реНрд░реЛрддреЛрдВ рдХреА рдПрдХ рд╕реВрдЪреА рд╣реИред рд╣рдо рдСрдкрд░реЗрдЯрд░ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдЗрд╕реЗ "рд╕рдмреНрд╕рдХреНрд░рд╛рдЗрдм" рдХрд░рддреЗ рд╣реИрдВ assign (to: \.sources, on: self), рд╣рдореЗрдВ рдЙрди рд╕реВрдЪрдирд╛ рд╕реНрд░реЛрддреЛрдВ рдХреА рд╕реВрдЪреА рдорд┐рд▓рддреА рд╣реИ рдЬрд┐рдирдХреА рд╣рдореЗрдВ рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реЛрддреА рд╣реИ  sourcesред рдФрд░ рдСрдкрд░реЗрдЯрд░ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ AnyCancellableрдПрдХ рдЪрд░ рдореЗрдВ рдкреНрд░рд╛рдкреНрдд "рд╕рджрд╕реНрдпрддрд╛"  рдХреЛ рдпрд╛рдж рд░рдЦреЗрдВ  ред рдЕрдм рдЬрдм рд╣рдорд╛рд░реЗ рдкрд╛рд╕ рд╣рдорд╛рд░реА рдЬрд╛рдирдХрд╛рд░реА рдХреЗ рд╕реНрд░реЛрдд рд╣реИрдВ, рддреЛ рд╣рдо рдмрдирд╛рдирд╛ рд╢реБрд░реВ рдХрд░рддреЗ рд╣реИрдВ ред B рд╕реЗ рд╕рд┐рдВрдХ рд╕реАcancellableSet.store ( in: &self.cancellableSet)

View Model UISwiftUI ViewObservableObject рдореЙрдбрд▓ рдПрдХ @ObservedObjectрдЪрд░ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддрд╛ рд╣реИ рдЬреЛ рдЗрд╕ рдореЙрдбрд▓ рдХреЗ рд╡рд░реНрдЧ рдХреА рдПрдХ рдЖрд╡реГрддреНрддрд┐ рдХреЛ рд╕рдВрджрд░реНрднрд┐рдд рдХрд░рддрд╛ рд╣реИред рдПрдХ рдЪрд░ рдХреЗ рд░реВрдк рдореЗрдВ

рд╕рдВрд░рдЪрдирд╛ рдореЗрдВ ContentViewSources рд╡рд░реНрдЧ рдЙрджрд╛рд╣рд░рдг рдЬреЛрдбрд╝реЗрдВ  , рдкреНрд░рддреНрдпреЗрдХ 3 рдЧреБрдгреЛрдВ рдХреЗ рд▓рд┐рдП   рдЕрдкрдирд╛ рд╕реНрд╡рдпрдВ рдХрд╛ рд╕реНрдерд╛рди рдирд┐рдХрд╛рд▓реЗрдВ  рдФрд░ рд░рдЦреЗрдВ  :SourcesViewModelvar sourcesViewModelText ("Hello, World!")View@Published sourcesViewModel

 
  • SearchViewрдЦреЛрдЬ рдмрд╛рд░ рдХреЗ рд▓рд┐рдП  рдЯреЗрдХреНрд╕реНрдЯ рдмреЙрдХреНрд╕  searchString,
  •  Picker рджреЗрд╢ рдХреЗ рд▓рд┐рдП country,
  • SourcesList рд╕реВрдЪрдирд╛ рдХреЗ рд╕реНрд░реЛрддреЛрдВ рдХреА рд╕реВрдЪреА 



рдирддреАрдЬрддрди, рд╣рдореЗрдВ рд╡рд╣ рдорд┐рд▓рддрд╛ рд╣реИ рдЬрд┐рд╕рдХреА рд╣рдореЗрдВ рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реЛрддреА рд╣реИ View:



рдЗрд╕ рд╕реНрдХреНрд░реАрди рдкрд░, рд╣рдо рдХреЗрд╡рд▓ рдкрд╛рда рдмреЙрдХреНрд╕ SearchViewрдФрд░ "рджреЗрд╢"  рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдЦреЛрдЬ рд╕реНрдЯреНрд░рд┐рдВрдЧ рдХрд╛ рдкреНрд░рдмрдВрдзрди рдХрд░рддреЗ рд╣реИрдВ Picker, рдФрд░ рдмрд╛рдХреА рд╕реНрд╡рдЪрд╛рд▓рд┐рдд рд░реВрдк рд╕реЗ рд╣реЛрддрд╛ рд╣реИред

рд╕реВрдЪрдирд╛ рд╕реНрд░реЛрддреЛрдВ рдХреА рд╕реВрдЪреА SourcesListрдореЗрдВ рдкреНрд░рддреНрдпреЗрдХ рд╕реНрд░реЛрдд рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдиреНрдпреВрдирддрдо рдЬрд╛рдирдХрд╛рд░реА рд╣реЛрддреА рд╣реИ - рдирд╛рдо source.name рдФрд░ рдПрдХ рд╕рдВрдХреНрд╖рд┐рдкреНрдд рд╡рд┐рд╡рд░рдг source.description:



... рд▓реЗрдХрд┐рди рдпрд╣ рдЖрдкрдХреЛ рд▓рд┐рдВрдХ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдЪрдпрдирд┐рдд рд╕реНрд░реЛрдд рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдЕрдзрд┐рдХ рд╡рд┐рд╕реНрддреГрдд рдЬрд╛рдирдХрд╛рд░реА рдкреНрд░рд╛рдкреНрдд рдХрд░рдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рджреЗрддрд╛ NavigationLinkрд╣реИ рдЬрд┐рд╕рдореЗрдВ destinationрд╣рдо рд╕рдВрдХреЗрдд рджреЗрддреЗ рд╣реИрдВ рдХрд┐  DetailSourceViewрдХреМрди рд╕рд╛ рд╕реНрд░реЛрдд рдбреЗрдЯрд╛ рдЬрд╛рдирдХрд╛рд░реА рдХрд╛ рд╕реНрд░реЛрдд  sourceрдФрд░ рдЖрд╡рд╢реНрдпрдХ рд╡рд░реНрдЧ рдЙрджрд╛рд╣рд░рдг рд╣реИ ArticlesViewModel, рдЬреЛ рдЕрдиреБрдорддрд┐ рджреЗрддрд╛ рд╣реИ рдЙрдирдХреЗ рд▓реЗрдЦреЛрдВ рдХреА рдПрдХ рд╕реВрдЪреА рдкреНрд░рд╛рдкреНрдд рдХрд░реЗрдВ articles:



рдпрд╣ рджреЗрдЦреЗрдВ рдХрд┐ рд╕реНрд░реЛрддреЛрдВ рдХреА рд╕реВрдЪреА рдореЗрдВ рд╕реВрдЪрдирд╛ рд╕реНрд░реЛрдд рдХреЗ рдЪрдпрдирд┐рдд рд╕реНрд░реЛрдд рдХреЗ рд▓рд┐рдП рд▓реЗрдЦреЛрдВ рдХреА рд╕реВрдЪреА рд╣рдореЗрдВ рдХрд┐рддрдиреА рднрд╡реНрдпрддрд╛ рд╕реЗ рдорд┐рд▓рддреА рд╣реИ  SourcesListред рд╣рдорд╛рд░рд╛ рдкреБрд░рд╛рдирд╛ рдорд┐рддреНрд░ рд╣рдорд╛рд░реА рд╕рд╣рд╛рдпрддрд╛ рдХрд░рддрд╛ рд╣реИ - рдПрдХ рдРрд╕рд╛ рд╡рд░реНрдЧ  ArticlesViewModelрдЬрд┐рд╕рдХреЗ рд▓рд┐рдП рд╣рдореЗрдВ "рдЗрдирдкреБрдЯ" рджреЛрдиреЛрдВ @PublishedрдЧреБрдг рд╕реЗрдЯ рдХрд░рдиреЗ рд╣реЛрдВрдЧреЗ  :

  • рд╕реВрдЪрдХрд╛рдВрдХ indexEndpoint = 3, рдЕрд░реНрдерд╛рддреН  , .articlesFromSource (_source:String)рдПрдХ рдирд┐рд╢реНрдЪрд┐рдд рд╕реНрд░реЛрдд рдХреЗ рд▓рд┐рдП рд▓реЗрдЦреЛрдВ рдХреЗ рдЪрдпрди рдХреЗ рд▓рд┐рдП рдПрдХ рд╡рд┐рдХрд▓реНрдк  source,
  • searchString рд╕реНрд░реЛрдд рдХреЗ рд░реВрдк рдореЗрдВ рд╕реНрдЯреНрд░рд┐рдВрдЧ  (рдпрд╛ рдЗрд╕рдХреЗ рдкрд╣рдЪрд╛рдирдХрд░реНрддрд╛) source.id :



рд╕рд╛рдорд╛рдиреНрдп рддреМрд░ рдкрд░, рдпрджрд┐ рдЖрдк рдкреВрд░реЗ NewsApp рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдХреЛ рджреЗрдЦрддреЗ рд╣реИрдВ, рддреЛ рдЖрдк рдХрд╣реАрдВ рднреА рдирд╣реАрдВ рджреЗрдЦреЗрдВрдЧреЗ рдХрд┐ рд╣рдо рд╕реНрдкрд╖реНрдЯ рд░реВрдк рд╕реЗ NewsAPI.org рд╡реЗрдмрд╕рд╛рдЗрдЯ рд╕реЗ рд▓реЗрдЦ рдпрд╛ рд╕реВрдЪрдирд╛ рд╕реНрд░реЛрддреЛрдВ рдХреЗ рдЪрдпрди рдХрд╛ рдЕрдиреБрд░реЛрдз рдХрд░рддреЗ рд╣реИрдВ  ред рд╣рдо рдХреЗрд╡рд▓ @Published рдбреЗрдЯрд╛ рдХрд╛ рдкреНрд░рдмрдВрдзрди  рдХрд░рддреЗ рд╣реИрдВ, рд▓реЗрдХрд┐рди View Model рд╣рдорд╛рд░рд╛ рдХрд╛рдо рдХрд░рддрд╛ рд╣реИ: рд╣рдореЗрдВ рдЙрди рд▓реЗрдЦреЛрдВ рдФрд░ рд╕реВрдЪрдирд╛рдУрдВ рдХреЗ рд╕реНрд░реЛрддреЛрдВ рдХрд╛ рдЪрдпрди рдХрд░рдирд╛ рдЪрд╛рд╣рд┐рдП рдЬрд┐рдирдХреА рд╣рдореЗрдВ рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИред

UIImageрд▓реЗрдЦ рдХреЗ рд▓рд┐рдП рдЫрд╡рд┐ рдбрд╛рдЙрдирд▓реЛрдб рдХрд░реЗрдВ Articleред


рд▓реЗрдЦ рдХреЗ рдореЙрдбрд▓  Article рдореЗрдВ рдПрдХ URLрдЫрд╡рд┐ рд╣реЛрддреА рд╣реИ urlToImageрдЬреЛ рдЗрд╕рдХреЗ рд╕рд╛рде рд╣реЛрддреА рд╣реИ  : рдЗрд╕рдХреЗ



рдЖрдзрд╛рд░ рдкрд░,  URLрднрд╡рд┐рд╖реНрдп рдореЗрдВ рд╣рдореЗрдВ NewsAPI.orgUIImage  рд╡реЗрдмрд╕рд╛рдЗрдЯ рд╕реЗ рд╕реНрд╡рдпрдВ рдЪрд┐рддреНрд░ рдкреНрд░рд╛рдкреНрдд рдХрд░рдиреЗ  рд╣реЛрдВрдЧреЗ ред

рд╣рдо рдкрд╣рд▓реЗ рд╕реЗ рд╣реА рдЗрд╕ рдХрд╛рд░реНрдп рд╕реЗ рдкрд░рд┐рдЪрд┐рдд рд╣реИрдВред рд╡рд░реНрдЧ рдореЗрдВ ImageLoader, рдлрд╝рдВрдХреНрд╢рди рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ, рдЫрд╡рд┐ рдорд╛рди рдХреЗ рд╕рд╛рде  fetchImage(for url: URL?) -> AnyPublisher<UIImage?, Never>рдПрдХ "рдкреНрд░рдХрд╛рд╢рдХ" рдмрдирд╛рдПрдВ   рдФрд░ рдХреЛрдИ рддреНрд░реБрдЯрд┐ рдирд╣реАрдВ рд╣реИ  (рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ, рдпрджрд┐ рддреНрд░реБрдЯрд┐рдпрд╛рдВ рд╣реЛрддреА рд╣реИрдВ, рддреЛ рдЫрд╡рд┐ рд╡рд╛рдкрд╕ рдЖ рдЬрд╛рддреА рд╣реИ )ред  рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдЗрдВрдЯрд░рдлрд╝реЗрд╕ ( ) рдбрд┐рдЬрд╝рд╛рдЗрди рдХрд░рддреЗ рд╕рдордп рдЫрд╡рд┐рдпреЛрдВ рдХреЛ рдкреНрд░рд╛рдкреНрдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЖрдк рдЗрд╕ "рдкреНрд░рдХрд╛рд╢рдХ" рдХреЛ "рд╕рджрд╕реНрдпрддрд╛" рджреЗ рд╕рдХрддреЗ рд╣реИрдВ  ред рдлрд╝рдВрдХреНрд╢рди рдХрд╛ рд╕реНрд░реЛрдд рдбреЗрдЯрд╛ рд╣реИ  , рдЬреЛ рд╣рдорд╛рд░реЗ рдкрд╛рд╕ рд╣реИ:AnyPublisher<UIImage?, Never>UIImage?Never nilUIImage?UIfetchImage(for url: URL?)url



рдЖрдЗрдП рд╡рд┐рд╕реНрддрд╛рд░ рд╕реЗ рд╡рд┐рдЪрд╛рд░ рдХрд░реЗрдВ рдХрд┐ Combine"рдкреНрд░рдХрд╛рд╢рдХ" рдХреА рдорджрдж рд╕реЗ рдЧрдарди рдХреИрд╕реЗ рдЪрд▓ рд░рд╣рд╛ рд╣реИ AnyPublisher <UIImage?, Never>, рдЕрдЧрд░ рд╣рдо рдЬрд╛рдирддреЗ рд╣реИрдВ url:

  1. рдЕрдЧрд░ urlрдмрд░рд╛рдмрд░ рд╣реИ nil, рд▓реМрдЯрд╛рдУ Just(nil),
  2. рдХреЗ рдЖрдзрд╛рд░ рдкрд░ url"рдкреНрд░рдХрд╛рд╢рдХ" рдХреЗ рд░реВрдк dataTaskPublisher(for:)рд╣реИ, рдЬрд┐рд╕рдХрд╛ рдЙрддреНрдкрд╛рджрди рдореВрд▓реНрдп OutputрдПрдХ рдЯрдкрд▓ рд╣реИ (data: Data, response: URLResponse)рдФрд░ рдПрдХ рддреНрд░реБрдЯрд┐  FailureURLError,
  3. рд╣рдо рдЖрдЧреЗ рдХреА рдкреНрд░рдХреНрд░рд┐рдпрд╛ рдФрд░ рдлрд╝реЙрд░реНрдо рдХреЗ рд▓рд┐рдП рдХреЗрд╡рд▓ map {}рдЯрдкрд▓ рд╕реЗ (data: Data, response: URLResponse)рдбреЗрдЯрд╛  рд▓реЗрддреЗ рд╣реИрдВ ,dataUIImage
  4. рдпрджрд┐ рдкрд┐рдЫрд▓реЗ рдЪрд░рдг рд╡рд╛рдкрд╕реА рддреНрд░реБрдЯрд┐ рд╣реЛрддреА рд╣реИ nil,
  5. рд╣рдо mainрд╕реНрдЯреНрд░реАрдо рдХреЛ рдкрд░рд┐рдгрд╛рдо рджреЗрддреЗ рд╣реИрдВ, рдЬреИрд╕рд╛ рдХрд┐ рд╣рдо рдбрд┐рдЬрд╝рд╛рдЗрди рдореЗрдВ рдЖрдЧреЗ рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рд╣реИрдВ UI,
  6. "рдкреНрд░рдХрд╛рд╢рдХ" рдХреЗ рдкреНрд░рдХрд╛рд░ "рдорд┐рдЯрд╛" рдФрд░ рдкреНрд░рддрд┐рд▓рд┐рдкрд┐ рд╡рд╛рдкрд╕ рдХрд░реЗрдВ AnyPublisherред

рдЖрдк рджреЗрдЦрддреЗ рд╣реИрдВ рдХрд┐ рдХреЛрдб рдХрд╛рдлреА рдХреЙрдореНрдкреИрдХреНрдЯ рдФрд░ рдЕрдЪреНрдЫреА рддрд░рд╣ рд╕реЗ рдкрдардиреАрдп рд╣реИ, рдХреЛрдИ рднреА рдирд╣реАрдВ рд╣реИ callbacksред

рдЖрдЗрдП View Model рдЫрд╡рд┐ рдХреЗ рд▓рд┐рдП рдмрдирд╛рдирд╛ рд╢реБрд░реВ  рдХрд░реЗрдВ UIImage?ред рдпрд╣ рдПрдХ рд╡рд░реНрдЧ ImageLoaderрд╣реИ рдЬреЛ рдкреНрд░реЛрдЯреЛрдХреЙрд▓ рдХреЛ рд▓рд╛рдЧреВ рдХрд░рддрд╛ рд╣реИ ObservableObject, рдЬрд┐рд╕рдореЗрдВ рджреЛ  @PublishedрдЧреБрдг рд╣реЛрддреЗ рд╣реИрдВ:

  • @Published url: URL? рдХрд░ рд░рд╣реЗ рд╣реИрдВ URLрдЫрд╡рд┐рдпреЛрдВ
  • @Published var image: UIImage?NewsAPI.org  рд╕реЗ рд╣реА рдЫрд╡рд┐ рд╣реИ :



рдФрд░ рдлрд┐рд░ рд╕реЗ, рдХрдХреНрд╖рд╛ рдХреЗ рдПрдХ рдЙрджрд╛рд╣рд░рдг рдХреЛ рд╢реБрд░реВ рдХрд░рддреЗ рд╕рдордп,  ImageLoader рд╣рдореЗрдВ "рдкреНрд░рдХрд╛рд╢рдХ" рдЗрдирдкреБрдЯ рд╕реЗ рд╢реНрд░реГрдВрдЦрд▓рд╛ $url рдХреЛ рдЖрдЙрдЯрдкреБрдЯ "рдкреНрд░рдХрд╛рд╢рдХ" рддрдХ рдлреИрд▓рд╛рдирд╛ рд╣реЛрдЧрд╛  AnyPublisher<UIImage?, Never>, рдЬрд┐рд╕реЗ рд╣рдо рдмрд╛рдж рдореЗрдВ  "рд╕рджрд╕реНрдпрддрд╛ рд▓реЗрдВрдЧреЗ " рдФрд░ рд╣рдореЗрдВ рдЬрд┐рд╕ рдЫрд╡рд┐ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ рдЙрд╕реЗ рдкреНрд░рд╛рдкреНрдд рдХрд░реЗрдВ image:



рд╣рдо рдЗрд╕реЗ "рдкреНрд░рдХрд╛рд╢рдХ" рд╕реЗ рдкреНрд░рд╛рдкреНрдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдСрдкрд░реЗрдЯрд░  flatMapрдФрд░ рдПрдХ рдмрд╣реБрдд рд╣реА рд╕рд░рд▓ рдЧреНрд░рд╛рд╣рдХ рдХрд╛  рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рд╣реИрдВред assign (to: \image, on: self)"рд╕рдВрдкрддреНрддрд┐ рдХрд╛ рдореВрд▓реНрдп @Published image:



рдФрд░ рдЪрд░ рдореЗрдВ рдлрд┐рд░ рд╕реЗ  " рд╕рджрд╕реНрдпрддрд╛ "рдСрдкрд░реЗрдЯрд░ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ  cancellableSet рд╕рдВрдЧреНрд░рд╣реАрдд рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ ред рдЗрд╕ "рдЫрд╡рд┐ рдбрд╛рдЙрдирд▓реЛрдбрд░" рдХрд╛ рддрд░реНрдХ рдпрд╣ рд╣реИ рдХрд┐ рдЖрдк рдПрдХ рдЫрд╡рд┐ рдХреЛ рдХрд┐рд╕реА рдЕрдиреНрдп рдЪреАрдЬрд╝ рд╕реЗ рдбрд╛рдЙрдирд▓реЛрдб рдХрд░рддреЗ рд╣реИрдВ, рдмрд╢рд░реНрддреЗ рдХрд┐ рд╡рд╣ рдкреНрд░реАрд▓реЛрдб рди рд╣реЛ, рдЬреЛ рд╣реИAnyCancellablestore(in: &self.cancellableSet)

nil URLimage == nilред рдпрджрд┐ рдбрд╛рдЙрдирд▓реЛрдб рдкреНрд░рдХреНрд░рд┐рдпрд╛ рдХреЗ рджреМрд░рд╛рди рдХрд┐рд╕реА рднреА рддреНрд░реБрдЯрд┐ рдХрд╛ рдкрддрд╛ рдЪрд▓рд╛ рд╣реИ, рддреЛ рдЫрд╡рд┐ рдЕрдиреБрдкрд╕реНрдерд┐рдд рд╣реЛрдЧреА, рдЕрд░реНрдерд╛рдд рдпрд╣ imageрдмрд░рд╛рдмрд░ рд░рд╣реЗрдЧреА nilред

рдореЗрдВ SwiftUIрд╣рдо рдорджрдж рд╕реЗ рдЫрд╡рд┐ рджрд┐рдЦрд╛рдиреЗ ArticleImageрдХрд╛ рдПрдХ рдЙрджрд╛рд╣рд░рдг рд╣реИ рдХрд┐ imageLoader рд╡рд░реНрдЧ рдЗрд╕ рдХреЗ рд▓рд┐рдП рдЙрдкрдпреЛрдЧ рдХрд░рддрд╛ рд╣реИ ImageLoaderред рдпрджрд┐ рдЙрд╕рдХреА рдЫрд╡рд┐ рдХреА рдЫрд╡рд┐ рд╕рдорд╛рди рдирд╣реАрдВ рд╣реИ nil, рддреЛ рдЗрд╕рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдкреНрд░рджрд░реНрд╢рд┐рдд рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ Image (...), рд▓реЗрдХрд┐рди рдпрджрд┐ рдпрд╣ рд╕рдорд╛рди рд╣реИ nil, рддреЛ рдЗрд╕рдХреЗ рдмрд░рд╛рдмрд░ рдХреНрдпрд╛ рд╣реИ, рдЗрд╕рдХреЗ рдЖрдзрд╛рд░ рдкрд░ url , рдпрд╛ рддреЛ рдХреБрдЫ рднреА рдирд╣реАрдВ рджрд┐рдЦрд╛рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ EmptyView(), рдпрд╛ RectangleрдШреВрд░реНрдгрди рдкрд╛рда рдЯреА рдХреЗ рд╕рд╛рде рдПрдХ рдЖрдпрдд рдкреНрд░рджрд░реНрд╢рд┐рдд рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ ext("Loading..."):



рдпрд╣ рддрд░реНрдХ рдорд╛рдорд▓реЗ рдХреЗ рд▓рд┐рдП рдареАрдХ рдХрд╛рдо рдХрд░рддрд╛ рд╣реИ рдЬрдм рдЖрдк рдпрд╣ рд╕реБрдирд┐рд╢реНрдЪрд┐рдд рдХрд░ рд▓реЗрддреЗ рд╣реИрдВ рдХрд┐  рдЖрдк рдХреЗ urlрдЕрд▓рд╛рд╡рд╛,  nilрдЖрдкрдХреЛ рдПрдХ рдЫрд╡рд┐ рдорд┐рд▓рддреА рд╣реИ image, рдЬреИрд╕рд╛ рдХрд┐ рдореВрд╡реА рдбреЗрдЯрд╛рдмреЗрд╕ рдХреЗ рдорд╛рдорд▓реЗ рдореЗрдВ рд╣реИ TMDb ред NewsAPI.org рдХреЗ рд╕рд╛рде , рд╕рдорд╛рдЪрд╛рд░ рдПрдЧреНрд░реАрдЧреЗрдЯрд░    рдЕрд▓рдЧ рд╣реИред рдЬрд╛рдирдХрд╛рд░реА рдХреЗ рдХреБрдЫ рд╕реНрд░реЛрддреЛрдВ рдХреЗ рд▓реЗрдЦ nil URLрдЫрд╡рд┐ рд╕реЗ рдПрдХ рдЕрд▓рдЧ рд╕рдВрдХреЗрдд рджреЗрддреЗ рд╣реИрдВ  , рд▓реЗрдХрд┐рди рдЗрд╕рдХреА рдкрд╣реБрдВрдЪ рдмрдВрдж рд╣реИ, рдФрд░ рд╣рдореЗрдВ RectangleрдШреВрдорддреЗ рд╣реБрдП рдкрд╛рда рдХреЗ рд╕рд╛рде рдПрдХ рдЖрдпрдд рдорд┐рд▓рддреА рд╣реИ Text("Loading...")рдЬрд┐рд╕реЗ рдХрднреА рднреА рдкреНрд░рддрд┐рд╕реНрдерд╛рдкрд┐рдд рдирд╣реАрдВ рдХрд┐рдпрд╛ рдЬрд╛рдПрдЧрд╛:



рдЗрд╕ рд╕реНрдерд┐рддрд┐ рдореЗрдВ, рдпрджрд┐  URLрдЫрд╡рд┐ рдЗрд╕рд╕реЗ рднрд┐рдиреНрди рд╣реИ  nil, рддреЛ nilрдЫрд╡рд┐  рдХреА рд╕рдорд╛рдирддрд╛ рдпрд╣  imageрд╣реЛ рд╕рдХрддреА рд╣реИ рдХрд┐ рдЫрд╡рд┐ рд▓реЛрдб рд╣реЛ рд░рд╣реА рд╣реИ , рдФрд░ рдпрд╣ рддрдереНрдп рдХрд┐ рд▓реЛрдб рдХрд░рддреЗ рд╕рдордп рдПрдХ рддреНрд░реБрдЯрд┐ рд╣реБрдИ рдФрд░ рд╣рдореЗрдВ рдХрднреА рднреА рдЫрд╡рд┐ рдирд╣реАрдВ рдорд┐рд▓реЗрдЧреА imageред рдЗрди рджреЛ рд╕реНрдерд┐рддрд┐рдпреЛрдВ рдХреЗ рдмреАрдЪ рдЕрдВрддрд░ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рд╣рдо рдХрдХреНрд╖рд╛ рдореЗрдВ ImageLoader рджреЛ рдореМрдЬреВрджрд╛ @PublishedрдЧреБрдгреЛрдВ рдореЗрдВ рдПрдХ рдФрд░ рдЬреЛрдбрд╝рддреЗ рд╣реИрдВ 

 @Published var noData = false - рдпрд╣ рдПрдХ рдмреВрд▓рд┐рдпрди рдорд╛рди рд╣реИ рдЬрд┐рд╕рдХреЗ рд╕рд╛рде рд╣рдо рдЪрдпрди рдХреЗ рджреМрд░рд╛рди рдПрдХ рддреНрд░реБрдЯрд┐ рдХреЗ рдХрд╛рд░рдг рдЫрд╡рд┐ рдбреЗрдЯрд╛ рдХреА рдЕрдиреБрдкрд╕реНрдерд┐рддрд┐ рдХреЛ рдирд┐рд░реВрдкрд┐рдд рдХрд░реЗрдВрдЧреЗ:



"рд╕рджрд╕реНрдпрддрд╛" рдмрдирд╛рддреЗ рд╕рдордп, рд╣рдо initрд╕рднреА рддреНрд░реБрдЯрд┐рдпреЛрдВ рдХреЛ рдкрдХрдбрд╝рддреЗ рд╣реИрдВ ErrorрдЬреЛ рдЫрд╡рд┐ рдХреЛ рд▓реЛрдб рдХрд░рддреЗ рд╕рдордп рд╣реЛрддреА рд╣реИрдВ рдФрд░ @Publishedрд╕рдВрдкрддреНрддрд┐ рдореЗрдВ рдЙрдирдХреА рдЙрдкрд╕реНрдерд┐рддрд┐ рдХреЛ рдЬрдорд╛ рдХрд░рддреА  рд╣реИрдВ self.noData = trueред рдпрджрд┐ рдбрд╛рдЙрдирд▓реЛрдб рд╕рдлрд▓ рд░рд╣рд╛, рддреЛ рд╣рдо рдЫрд╡рд┐ рдкреНрд░рд╛рдкреНрдд рдХрд░рддреЗ рд╣реИрдВ imageред рд╣рдо  рдлрд╝рдВрдХреНрд╢рди  рдХреЗ рдЖрдзрд╛рд░ рдкрд░ 

"рдкреНрд░рдХрд╛рд╢рдХ"  рдмрдирд╛рддреЗ рд╣реИрдВ : рд╣рдо "рдкреНрд░рдХрд╛рд╢рдХ" рдХреЛ рдЗрдирд┐рд╢рд┐рдпрд▓рд╛рдЗрдЬрд╝ рдХрд░рдХреЗ  рдПрдХ рд╡рд┐рдзрд┐ рдмрдирд╛рдирд╛ рд╢реБрд░реВ рдХрд░рддреЗ рд╣реИрдВ , рдЬрд┐рд╕рдХрд╛ рдЙрдкрдпреЛрдЧ рдПрдХ рдмрдВрдж рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдПрдХ рдПрдХрд▓ TYPE рдорд╛рди рдкреНрд░рд╛рдкреНрдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ ред рдХреНрд▓реЛрдЬрд░ рдореЗрдВ рдПрдХ рдкреИрд░рд╛рдореАрдЯрд░ рд╣реИ - рдЬреЛ рдХрд┐ TYPE рдХрд╛ рдПрдХ рдлрд╝рдВрдХреНрд╢рди рд╣реИ  : рд╣рдо рдкрд░рд┐рдгрд╛рдорд╕реНрд╡рд░реВрдк рдХреЛ рдЪрд╛рд▓реВ рдХрд░реЗрдВрдЧреЗAnyPublisher<UIImage?, Error>urlfetchImageErr (for url: URL?)



fetchImageErrFutureResultPromise(Result<Output, Failure>) тЖТ Void



FutureAnyPublisher <UIImage?, Error>"рдорд┐рдЯрд╛ рдкреНрд░рдХрд╛рд░" рдСрдкрд░реЗрдЯрд░ рдХреА рдорджрдж рд╕реЗ eraseToAnyPublisher()ред

рдЗрд╕рдХреЗ рдмрд╛рдж, рд╣рдо рдирд┐рдореНрди рдЪрд░рдгреЛрдВ рдХрд╛ рдкрд╛рд▓рди рдХрд░реЗрдЧрд╛, (рд╣рдо рддреНрд░реБрдЯрд┐рдпреЛрдВ рдХреА рдкрд╣рдЪрд╛рди рдирд╣реАрдВ рд╣реЛрдЧрд╛, рдпрд╣ рдХреЗрд╡рд▓ рдорд╣рддреНрд╡рдкреВрд░реНрдг рд╣реИ рд╣рдореЗрдВ рдкрддрд╛ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдХрд┐ рдХреЛрдИ рддреНрд░реБрдЯрд┐ рд╣реИ рдХрд┐) рдЦрд╛рддреЗ рдХреЗ рд▓рд┐рдП рд╕рднреА рд╕рдВрднрд╡ рддреНрд░реБрдЯрд┐рдпреЛрдВ рдХреЛ рдзреНрдпрд╛рди рдореЗрдВ рд░рдЦрдХрд░:

0. рдЬрд╛рдВрдЪ urlрдХреЗ рд▓рд┐рдП nil рдФрд░  noDataрдкрд░ trueрд╕реНрдерд╛рдирд╛рдВрддрд░рдг рдпрджрд┐ рд╣рд╛рдВ, рддреЛ рдлрд┐рд░ рддреНрд░реБрдЯрд┐ рд╡рд╛рдкрд╕, рдЕрдЧрд░ рдирд╣реАрдВ,: urlрдЖрдЧреЗ рд╕реЗ рд╢реНрд░реГрдВрдЦрд▓рд╛,
1. рдПрдХ "рдкреНрд░рдХрд╛рд╢рдХ" рдмрдирд╛рдПрдВ dataTaskPublisher(for:)рдЬрд┐рд╕рдХрд╛ рдЗрдирдкреБрдЯ рд╣реИ - urlрдФрд░ рдЖрдЙрдЯрдкреБрдЯ рдорд╛рди OutputрдПрдХ рдЯрдкрд▓ (data: Data, response: URLResponse)рдФрд░ рдПрдХ рддреНрд░реБрдЯрд┐ рд╣реИ  URLError,
2. tryMap { } рдкрд░рд┐рдгрд╛рдорд╕реНрд╡рд░реВрдк рдЯрдкрд▓ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рд╡рд┐рд╢реНрд▓реЗрд╖рдг рдХрд░реЗрдВ (data: Data, response: URLResponse): рдпрджрд┐ рдпрд╣ response.statusCodeрд╕реАрдорд╛ рдореЗрдВ рд╣реИ 200...299, рддреЛ рдЖрдЧреЗ рдХреА рдкреНрд░рдХреНрд░рд┐рдпрд╛ рдХреЗ рд▓рд┐рдП рд╣рдо рдХреЗрд╡рд▓ рдбреЗрдЯрд╛ рд▓реЗрддреЗ рд╣реИрдВ  dataред рдЕрдиреНрдпрдерд╛, рд╣рдо рдПрдХ рддреНрд░реБрдЯрд┐ "рдмрд╛рд╣рд░ рдлреЗрдВрдХ" (рдХреЛрдИ рдлрд░реНрдХ рдирд╣реАрдВ рдкрдбрд╝рддрд╛),
3. рд╣рдо map { }рдбреЗрдЯрд╛ рдХреЛ рдмрджрд▓рдиреЗ dataрдореЗрдВ UIImage,
4. рдХреЗ рд▓рд┐рдП рдкрд░рд┐рдгрд╛рдо рджреЗрдиреЗ mainрдХреЗ рдмрд╛рдж рд╕реЗ рд╣рдо рдорд╛рдирддреЗ рд╣реИрдВ рдХрд┐ рд╣рдо рдЗрд╕реЗ рдбрд┐рдЬрд╛рдЗрди рдореЗрдВ рдмрд╛рдж рдореЗрдВ рдЙрдкрдпреЛрдЧ рдХрд░реЗрдЧрд╛, рдзрд╛рд░рд╛ рдкреНрд░рдХреНрд░рд┐рдпрд╛ UI
- рд╣рдо рдкреНрд░рдпреЛрдЧ рдХрд░ рдкреНрд░рд╛рдкреНрдд "рдкреНрд░рдХрд╛рд╢рдХ" рдХреЗ рд▓рд┐рдП "рдЧреНрд░рд╛рд╣рдХ рдмрдиреЗрдВ" sinkрдЗрд╕рдХреЗ рдмрдВрдж рд╣реЛрдиреЗ receiveCompletionрдФрд░ receiveValue,
- 5. рдЕрдЧрд░ рд╣рдо receiveCompletion рдПрдХ рддреНрд░реБрдЯрд┐ рдкрд╛рддреЗ рд╣реИрдВ рдмрдВрдж рдореЗрдВ  error, рд╣рдо рд░рд┐рдкреЛрд░реНрдЯ рдЗрд╕рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рд╣реБрдП promise (.failure(error))),
- 6. рдХреНрд▓реЛрдЬрд░ рдореЗрдВ,  receiveValue рд╣рдо рдЖрд▓реЗрдЦреЛрдВ рдХреА рдПрдХ рд╕рд░рдгреА рдХреА рд╕рдлрд▓ рдкреНрд░рд╛рдкреНрддрд┐ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рд╕реВрдЪрд┐рдд рдХрд░рддреЗ рд╣реИрдВ promise (.success($0))ред
7. рд╣рдореЗрдВ рдпрд╛рдж рдЖрддрд╛ рд╣реИ рдХрд┐ "рдЖрд╡реГрддреНрддрд┐" рдкреНрд░рд╛рдкреНрдд рд╣реБрдИ рд╣реИ, рдЬреЛ рдЪрд░  cancellableSetрдореЗрдВ "рдЬреАрд╡рдирдХрд╛рд▓" рдХреЗ рднреАрддрд░ рд╡рд░реНрдЧ рдХреА рдЖрд╡реГрддреНрддрд┐ рдХреЛ рд╕реБрдирд┐рд╢реНрдЪрд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдкреНрд░рд╛рдкреНрдд рд╣реЛрддреА рд╣реИ ImageLoader,
8. рд╣рдо "рдкреНрд░рдХрд╛рд╢рдХ" рдХреЛ "рдорд┐рдЯрд╛" рджреЗрддреЗ рд╣реИрдВред рдФрд░ рдЙрджрд╛рд╣рд░рдг рд╡рд╛рдкрд╕ рдХрд░реЗрдВ AnyPublisherред

рд╣рдо рдЙрд╕ рд╕реНрдерд╛рди рдкрд░ рд▓реМрдЯрддреЗ рд╣реИрдВ ArticleImageрдЬрд╣рд╛рдВ рд╣рдо рдирдП @PublishedрдЪрд░ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░реЗрдВрдЧреЗ  noDataред рдЕрдЧрд░ рдХреЛрдИ рдЫрд╡рд┐ рдбреЗрдЯрд╛ рд╣реИ, рддреЛ рд╣рдо рдХреБрдЫ рднреА рдкреНрд░рджрд░реНрд╢рд┐рдд рдХрд░реЗрдЧрд╛ рдирд╣реАрдВ, рдпрд╣ рд╣реИ рдХрд┐ EmptyView ():



рдЕрдВрдд рдореЗрдВ, рд╣рдо рд╕реЗ рдбреЗрдЯрд╛ рдкреНрд░рджрд░реНрд╢рд┐рдд рдХрд░рдиреЗ рдореЗрдВ рд╣рдорд╛рд░реЗ рд╕рднреА рд╕рдВрднрд╛рд╡рдирд╛рдУрдВ рдкреИрдХ рдЬрд╛рдПрдЧрд╛ NewsAPI.org рдЦрдмрд░ рдПрдЧреНрд░реАрдЧреЗрдЯрд░ рдореЗрдВ TabView:



NewsAPI.org рд╕рд░реНрд╡рд░ рд╕реЗ JSON рдбреЗрдЯрд╛ рдХреЛ рд▓рд╛рдиреЗ рдФрд░ рдбреАрдХреЛрдб рдХрд░рддреЗ рд╕рдордп рддреНрд░реБрдЯрд┐рдпрд╛рдВ рдкреНрд░рджрд░реНрд╢рд┐рдд рдХрд░реЗрдВ  ред


NewsAPI.org рд╕рд░реНрд╡рд░ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рд╕рдордп,  рддреНрд░реБрдЯрд┐рдпрд╛рдВ рд╣реЛ рд╕рдХрддреА рд╣реИрдВ, рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рдЗрд╕ рддрдереНрдп рдХреЗ рдХрд╛рд░рдг рдХрд┐ рдЖрдкрдиреЗ рдЧрд▓рдд рдХреБрдВрдЬреА рдирд┐рд░реНрджрд┐рд╖реНрдЯ рдХреА рд╣реИ API-key, рдпрд╛ рдПрдХ рдбреЗрд╡рд▓рдкрд░ рдХрд╛ рдЯреИрд░рд┐рдл рд╣реИ рдЬрд┐рд╕рдореЗрдВ рдХреБрдЫ рднреА рдЦрд░реНрдЪ рдирд╣реАрдВ рд╣реЛрддрд╛ рд╣реИ, рдЕрдиреБрдордд рд╕рдВрдЦреНрдпрд╛ рдпрд╛ рдХреБрдЫ рдФрд░ рдХреА рд╕рдВрдЦреНрдпрд╛ рд╕реЗ рдЕрдзрд┐рдХ рд╣реИред рдЙрд╕реА рд╕рдордп, NewsAPI.org рд╕рд░реНрд╡рд░   рдЖрдкрдХреЛ HTTPрдХреЛрдб рдФрд░ рд╕рдВрдмрдВрдзрд┐рдд рд╕рдВрджреЗрд╢ рдкреНрд░рджрд╛рди рдХрд░рддрд╛ рд╣реИ :



рдЗрд╕ рддрд░рд╣ рдХреА рд╕рд░реНрд╡рд░ рддреНрд░реБрдЯрд┐ рдХреЛ рд╕рдВрднрд╛рд▓рдирд╛ рдЖрд╡рд╢реНрдпрдХ рд╣реИред рдЕрдиреНрдпрдерд╛, рдЖрдкрдХреЗ рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдХрд╛ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдЙрд╕ рд╕реНрдерд┐рддрд┐ рдореЗрдВ рд╣реЛрдЧрд╛ рдЬрдм рдЕрдЪрд╛рдирдХ, рдмрд┐рдирд╛ рдХрд┐рд╕реА рдХрд╛рд░рдг рдХреЗ рд▓рд┐рдП, NewsAPI.org рд╕рд░реНрд╡рд░   рдХрд┐рд╕реА рднреА рдЕрдиреБрд░реЛрдз рдХреЛ рд╕рдВрд╕рд╛рдзрд┐рдд рдХрд░рдирд╛ рдмрдВрдж рдХрд░ рджреЗрдЧрд╛ , рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдХреЛ рдкреВрд░реА рддрд░рд╣ рд╕реЗ рдЦрд╛рд▓реА рд╕реНрдХреНрд░реАрди рдХреЗ рд╕рд╛рде рдиреБрдХрд╕рд╛рди рдореЗрдВ рдЫреЛрдбрд╝ рджреЗрдЧрд╛ред

рдЕрдм рддрдХ, рдЬрдм NewsAPI.org рд╕рд░реНрд╡рд░ рд╕реЗ рд▓реЗрдЦ [Article]рдФрд░ рдЬрд╛рдирдХрд╛рд░реА рдХреЗ рд╕реНрд░реЛрдд рдХрд╛  рдЪрдпрди  [Source]рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ  рд╣рдордиреЗ рд╕рднреА рддреНрд░реБрдЯрд┐рдпреЛрдВ рдХреЛ рдирдЬрд░рдЕрдВрджрд╛рдЬ рдХрд░ рджрд┐рдпрд╛, рдФрд░ рдЙрдирдХреА рдЙрдкрд╕реНрдерд┐рддрд┐ рдХреЗ рдорд╛рдорд▓реЗ рдореЗрдВ рдЦрд╛рд▓реА рд╕рд░рдгрд┐рдпрд╛рдВ [Article]()рдФрд░  рдкрд░рд┐рдгрд╛рдорд╕реНрд╡рд░реВрдк  [Source]()ред

рддреНрд░реБрдЯрд┐ рд╕реЗ рдирд┐рдкрдЯрдиреЗ рдХреЗ рд╕рд╛рде рд╢реБрд░реБрдЖрдд рдХрд░рдирд╛, рдЪрд▓рд┐рдП рдореМрдЬреВрджрд╛ fetchArticles (from endpoint: Endpoint) -> AnyPublisher<[Article], Never> рд▓реЗрдЦ рдЪрдпрди NewsAPI рдкрджреНрдзрддрд┐ рдХреЗ рдЖрдзрд╛рд░ рдкрд░ рдХрдХреНрд╖рд╛ рдореЗрдВ рдПрдХ рдФрд░ рд╡рд┐рдзрд┐ рдмрдирд╛рддреЗ рд╣реИрдВ  fetchArticlesErr (from endpoint: Endpoint) -> AnyPublisher<[Article], NewsError>рдЬреЛ рди рдХреЗрд╡рд▓ рд▓реЗрдЦреЛрдВ рдХреА рдПрдХ рд╕рд░рдгреА рд▓реМрдЯрд╛рдПрдЧрд╛ [Article], рдмрд▓реНрдХрд┐ рдПрдХ рд╕рдВрднрд╛рд╡рд┐рдд рддреНрд░реБрдЯрд┐ рднреА рд╣реЛрдЧреА  NewsError:

func fetchArticlesErr(from endpoint: Endpoint) ->
                            AnyPublisher<[Article], NewsError> {

. . . . . . . .
}

рдпрд╣ рд╡рд┐рдзрд┐, рд╕рд╛рде рд╣реА рд╡рд┐рдзрд┐ fetchArticlesрдХреЛ рд╕реНрд╡реАрдХрд╛рд░ рдХрд░рддрд╛ рд╣реИ endpoint рдФрд░ рдЗрдирдкреБрдЯ рдкрд░ "рдкреНрд░рдХрд╛рд╢рдХ" рдХреЛ рд▓реЗрдЦреЛрдВ рдХреА рдПрдХ рд╕рд░рдгреА рдХреЗ рд░реВрдк рдореЗрдВ рдПрдХ рдореВрд▓реНрдп рдХреЗ рд╕рд╛рде рджреЗрддрд╛ рд╣реИ [Article], рд▓реЗрдХрд┐рди рддреНрд░реБрдЯрд┐ рдХреА рдЕрдиреБрдкрд╕реНрдерд┐рддрд┐ рдХреЗ рдмрдЬрд╛рдп Never, рд╣рдорд╛рд░реЗ рдкрд╛рд╕ рдЧрдгрдирд╛ рджреНрд╡рд╛рд░рд╛ рдкрд░рд┐рднрд╛рд╖рд┐рдд рдПрдХ рддреНрд░реБрдЯрд┐ рд╣реЛ рд╕рдХрддреА рд╣реИ NewsError:



рдЪрд▓реЛ "рдкреНрд░рдХрд╛рд╢рдХ" рдХреЛ рдкреНрд░рд╛рд░рдВрдн рдХрд░рдХреЗ рдПрдХ рдирдпрд╛ рддрд░реАрдХрд╛ рдмрдирд╛рдирд╛ рд╢реБрд░реВ рдХрд░реЗрдВ  Future, рдЬреЛ рд╣реЛ рд╕рдХрддрд╛ рд╣реИ ResultрдПрдХ рдмрдВрдж рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдПрдХ рдПрдХрд▓ TYPE рдореВрд▓реНрдп рдХреЛ рдЕрддреБрд▓реНрдпрдХрд╛рд▓рд┐рдХ рд░реВрдк рд╕реЗ рдкреНрд░рд╛рдкреНрдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЙрдкрдпреЛрдЧ рдХрд░реЗрдВ ред рдмрдВрдж рдХрд░рдиреЗ рдХрд╛ рдПрдХ рдкреИрд░рд╛рдореАрдЯрд░ рд╣реИ - PromiseрдЬреЛ рдХрд┐ рдЯрд╛рдЗрдк рдХрд╛ рдПрдХ рдХрд╛рд░реНрдп рд╣реИ  (Result<Output, Failure>) -> Void: рд╣рдо



рдкреНрд░рд╛рдкреНрдд FutureрдХреЛ "рдкреНрд░рдХрд╛рд╢рдХ" рдореЗрдВ рдмрджрд▓ рджреЗрдВрдЧреЗ, рд╣рдореЗрдВ  AnyPublisher <[Article], NewsError>"рдЯрд╛рдЗрдк" рдорд┐рдЯрд╛рдХрд░ рдСрдкрд░реЗрдЯрд░ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдирд╛ рд╣реЛрдЧрд╛ eraseToAnyPublisher()ред

рдирдИ рдкрджреНрдзрддрд┐ рдореЗрдВ рдЖрдЧреЗ, fetchArticlesErrрд╣рдо рдЙрди рд╕рднреА рдЪрд░рдгреЛрдВ рдХреЛ рджреЛрд╣рд░рд╛рдПрдВрдЧреЗ рдЬреЛ рд╣рдордиреЗ рд╡рд┐рдзрд┐ рдореЗрдВ рдЙрдард╛рдП рдереЗ fetchArticles, рд▓реЗрдХрд┐рди рд╣рдо рд╕рднреА рд╕рдВрднрд╛рд╡рд┐рдд рддреНрд░реБрдЯрд┐рдпреЛрдВ рдХреЛ рдзреНрдпрд╛рди рдореЗрдВ рд░рдЦреЗрдВрдЧреЗ:



  • 0. endpoint  URL endpoint.absoluteURL , url nil: nil, .urlError, тАФ url ,
  • 1. ┬л┬╗ dataTaskPublisher(for:), тАФ url, Output (data: Data, response: URLResponse)  URLError,
  • 2. tryMap { }  (data: Data, response: URLResponse): response.statusCode 200...299,  data. ┬л┬╗ .responseError,   data, String, ,
  • 3. JSON ,  NewsResponse,
  • 4. main , UI
  • ┬л┬╗ ┬л┬╗ sink receiveCompletion receiveValue,
    • 5.    receiveCompletion  error, promise (.failure(...))),
    • 6.   receiveValue promise (.success($0.articles)),
     
  • 7.  ┬л┬╗  var subscriptions, ┬л ┬╗ NewsAPI,
  • 8. ┬л┬╗ ┬л┬╗ AnyPublisher.

рдпрд╣ рдзреНрдпрд╛рди рджрд┐рдпрд╛ рдЬрд╛рдирд╛ рдЪрд╛рд╣рд┐рдП рдХрд┐ "рдкреНрд░рдХрд╛рд╢рдХ"  рдПрдХ рд╕рд░реНрд╡рд░ рддреНрд░реБрдЯрд┐ рдХреЗ рдорд╛рдорд▓реЗ рдореЗрдВ рдЙрд╕рдХреЗ рдкреНрд░реЛрдЯреЛрдЯрд╛рдЗрдк рд╕реЗ dataTaskPublisher(for:) рднрд┐рдиреНрди рд╣реЛрддрд╛ рд╣реИ dataTaskрдЬрдм рдпрд╣ response.statusCode рд╕реАрдорд╛ рдореЗрдВ рдирд╣реАрдВ рд╣реЛрддрд╛ рд╣реИ 200...299, рдпрд╣ рдЕрднреА рднреА рдПрдХ рдЯреБрдкрд▓ рдХреЗ рд░реВрдк рдореЗрдВ рд╕рдлрд▓ рдорд╛рди рдмрдЪрд╛рддрд╛ рд╣реИ (data: Data, response: URLResponse), рдФрд░ рдлреЙрд░реНрдо рдореЗрдВ рдХреЛрдИ рддреНрд░реБрдЯрд┐ рдирд╣реАрдВ рд╣реИ (Error, URLResponse?)ред рдЗрд╕ рд╕реНрдерд┐рддрд┐ рдореЗрдВ, рдЕрд╕рд▓реА рд╕рд░реНрд╡рд░ рддреНрд░реБрдЯрд┐ рдЬрд╛рдирдХрд╛рд░реА рдореЗрдВ рдирд┐рд╣рд┐рдд рд╣реИ dataред рдпрджрд┐ рдЧреНрд░рд╛рд╣рдХ рдХреА рдУрд░ рд╕реЗ рдХреЛрдИ рддреНрд░реБрдЯрд┐ рд╣реЛрддреА рд╣реИ (рд╕рд░реНрд╡рд░ рд╕реЗ рд╕рдВрдкрд░реНрдХ рдХрд░рдиреЗ рдореЗрдВ рдЕрд╕рдорд░реНрдерддрд╛, рд╕реБрд░рдХреНрд╖рд╛ рдкреНрд░рдгрд╛рд▓реА рдкреНрд░рддрд┐рдмрдВрдз рдЖрджрд┐) "рдкреНрд░рдХрд╛рд╢рдХ" dataTaskPublisher(for:) рдПрдХ рддреНрд░реБрдЯрд┐ рджреЗрддрд╛ рд╣реИ  ред рдпрджрд┐ рд╣рдо рддреНрд░реБрдЯрд┐рдпреЛрдВ рдХреЛ рдкреНрд░рджрд░реНрд╢рд┐рдд рдХрд░рдирд╛ рдЪрд╛рд╣рддреЗ рд╣реИрдВ , рддреЛ рд╣рдореЗрдВ рдЙрд╕реА рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ , рдЬрд┐рд╕реЗ рд╣рдо рдХрд╣реЗрдВрдЧреЗ  : рдкреНрд░реЛрдЯреЛрдХреЙрд▓ рд▓рд╛рдЧреВ рдХрд░рдиреЗ рд╡рд╛рд▓реЗ рд╡рд░реНрдЧ рдореЗрдВ , рдЗрд╕ рдмрд╛рд░ рд╣рдорд╛рд░реЗ рдкрд╛рд╕  рдЧреБрдг рд╣реИрдВ:URLErrorATS

SwiftUIView ModelArticlesViewModelErr



 ArticlesViewModelErrObservableObject @Published

  1. @Published var indexEndpoint: Int тАФ Endpoint ( ┬л┬╗, View), 
  2. @Published var searchString: String тАФ ,  Endpoint: ┬л┬╗ , ( ┬л┬╗, View), 
  3.  @Published var articles: [Article] - ( ┬л┬╗,  NewsAPI.org )
  4.   @Published var articlesError: NewsError? - ,    NewsAPI.org .

рдЬрдм рдЖрдк рдХрд┐рд╕реА рд╡рд░реНрдЧ рдХреЗ рдЙрджрд╛рд╣рд░рдг рдХреЛ рдЗрдирд┐рд╢рд┐рдпрд▓рд╛рдЗрдЬрд╝ рдХрд░рддреЗ рд╣реИрдВ ArticlesViewModelErr, рддреЛ рд╣рдореЗрдВ рдлрд┐рд░ рд╕реЗ рдЗрдирдкреБрдЯ "рдкрдмреНрд▓рд┐рд╢рд░реНрд╕" рд╕реЗ рдПрдХ рдЪреЗрди $indexEndpointрдФрд░ "рдкрдмреНрд▓рд┐рд╢рд░" $searchStringрдХреЛ рдЖрдЙрдЯрдкреБрдЯ рдХрд░рдирд╛ рд╣реЛрдЧрд╛  AnyPublisher<[Article],NewsError>, рдЬрд┐рд╕рдХреЗ рд▓рд┐рдП рд╣рдо "рд╕рдмреНрд╕рдХреНрд░рд╛рдЗрдмрд░" рдХреЗ рд╕рд╛рде "рд╕рд╛рдЗрди" рдХрд░реЗрдВ sinkрдФрд░ рд╣рдореЗрдВ рдмрд╣реБрдд рд╕рд╛рд░реЗ рдЖрд░реНрдЯрд┐рдХрд▓ articlesрдпрд╛ рдПрд░рд░ рдорд┐рд▓реЗрдВ  articlesErrorред

рд╣рдорд╛рд░реА рдХрдХреНрд╖рд╛ рдореЗрдВ, NewsAPIрд╣рдордиреЗ рдкрд╣рд▓реЗ рд╕реЗ рд╣реА fetchArticlesErr (from endpoint: Endpoint)рдПрдХ "рдкреНрд░рдХрд╛рд╢рдХ" рд▓реМрдЯрд╛рдП рдЬрд╛рдиреЗ рд╡рд╛рд▓реЗ рдлрд╝рдВрдХреНрд╢рди рдХрд╛ рдирд┐рд░реНрдорд╛рдг  рдХрд┐рдпрд╛ рд╣реИ  AnyPublisher<[Article], NewsError>, рдЬреЛ рдореВрд▓реНрдп рдкрд░ рдирд┐рд░реНрднрд░ рдХрд░рддрд╛ рд╣реИ endpoint, рдФрд░ рд╣рдореЗрдВ рдХреЗрд╡рд▓ "рдкреНрд░рдХрд╛рд╢рдХреЛрдВ" рдХреЗ рдореВрд▓реНрдпреЛрдВ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ  $indexEndpointрдФрд░  $searchStringрдЙрдиреНрд╣реЗрдВ рдЗрд╕ рдлрд╝рдВрдХреНрд╢рди рдХреЗ рддрд░реНрдХ рдореЗрдВ рдмрджрд▓рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ endpointред 

рдХреЗ рд╕рд╛рде рд╢реБрд░реВ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рд╣рдо "рдкреНрд░рдХрд╛рд╢рдХреЛрдВ" рдХреЛ рдЬреЛрдбрд╝ рджреЗрдВрдЧреЗ  $indexEndpoint рдФрд░  $searchStringред рдРрд╕рд╛ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, CombineрдПрдХ рдСрдкрд░реЗрдЯрд░ рд╣реИ Publishers.CombineLatest:



рдлрд┐рд░ рд╣рдореЗрдВ рдЖрд╡рд╢реНрдпрдХ рдХреЗ рдмрд░рд╛рдмрд░ рддреНрд░реБрдЯрд┐ рдкреНрд░рдХрд╛рд░ рдЯрд╛рдЗрдк "рдкреНрд░рдХрд╛рд╢рдХ" рд╕реЗрдЯ рдХрд░рдирд╛ рд╣реЛрдЧрд╛  NewsError:



рдЕрдЧрд▓рд╛, рд╣рдо fetchArticlesErr (from endpoint: Endpoint) рдЕрдкрдиреА рдХрдХреНрд╖рд╛ рд╕реЗ рдлрд╝рдВрдХреНрд╢рди рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдирд╛ рдЪрд╛рд╣рддреЗ рд╣реИрдВ  NewsAPIред рд╣рдореЗрд╢рд╛ рдХреА рддрд░рд╣, рд╣рдо рдПрдХ рдСрдкрд░реЗрдЯрд░ рдХреА рдорджрдж рд╕реЗ рдпрд╣ рдХрд░ рджреЗрдЧрд╛  flatMap: рдХрд┐ рдкрд┐рдЫрд▓реЗ "рдкреНрд░рдХрд╛рд╢рдХ" рд╕реЗ рдкреНрд░рд╛рдкреНрдд рдЖрдВрдХрдбрд╝реЛрдВ рдХреЗ рдЖрдзрд╛рд░ рдкрд░ рдПрдХ рдирдпрд╛ "рдкреНрд░рдХрд╛рд╢рдХ" рдмрдирд╛рддрд╛ рд╣реИ



рддреЛ рд╣рдо рдЗрд╕ рдирд╡ рдкреНрд░рд╛рдкреНрдд "рдкреНрд░рдХрд╛рд╢рдХ" рдХреЗ рд▓рд┐рдП "рдЧреНрд░рд╛рд╣рдХ рдмрдиреЗрдВ" рдПрдХ "рдЧреНрд░рд╛рд╣рдХ" рдХреА рдорджрдж рд╕реЗ sinkрдФрд░ рдЙрд╕рдХреЗ рдмрдВрдж рд╣реЛрдиреЗ рдХрд╛ рдЙрдкрдпреЛрдЧ receiveCompletionрдФрд░ receiveValue"рдкреНрд░рдХрд╛рд╢рдХ" рдпрд╛ рддреЛ рд▓реЗрдЦреЛрдВ рдХреА рдПрдХ рд╕рд░рдгреА articlesрдпрд╛ рдПрдХ рддреНрд░реБрдЯрд┐ рдХреЗ рдореВрд▓реНрдп рд╕реЗ рдкреНрд░рд╛рдкреНрдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП  articlesError:



рд╕реНрд╡рд╛рднрд╛рд╡рд┐рдХ рд░реВрдк рд╕реЗ, рдХреБрдЫ рдмрд╛рд╣рд░реА init()рдЪрд░ рдореЗрдВ рдкрд░рд┐рдгрд╛рдореА "рд╕рджрд╕реНрдпрддрд╛" рдХреЛ рдпрд╛рдж рд░рдЦрдирд╛ рдЖрд╡рд╢реНрдпрдХ рд╣реИ cancellableSetред рдЕрдиреНрдпрдерд╛, рд╣рдо рдореВрд▓реНрдп рдХреЛ рдЕрддреБрд▓реНрдпрдХрд╛рд▓рд┐рдХ рд░реВрдк рд╕реЗ рдкреНрд░рд╛рдкреНрдд рдХрд░рдиреЗ рдореЗрдВ рд╕рдХреНрд╖рдо рдирд╣реАрдВ рд╣реЛрдВрдЧреЗarticlesрдпрд╛ рдХреЛрдИ рддреНрд░реБрдЯрд┐ articlesError рдкреВрд░рд╛ рд╣реЛрдиреЗ рдХреЗ рдмрд╛рдж init():



рдЖрджреЗрд╢ рдЬрдм рдПрдХ рдЦреЛрдЬ рд╕реНрдЯреНрд░рд┐рдВрдЧ рдЯрд╛рдЗрдкрд┐рдВрдЧ рд╕рд░реНрд╡рд░ рд╕реЗ рдХреЙрд▓ рдХреА рд╕рдВрдЦреНрдпрд╛ рдХрдо рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП searchString, рд╣рдо рдЦреЛрдЬ рдкрдЯреНрдЯреА рдХреЗ рд╣реА "рдкреНрд░рдХрд╛рд╢рдХ" рдЙрдкрдпреЛрдЧ рдирд╣реАрдВ рдХрд░рдирд╛ рдЪрд╛рд╣рд┐рдП  $searchString, рд▓реЗрдХрд┐рди рдЗрд╕рдХреЗ рд╕рдВрд╢реЛрдзрд┐рдд рд╕рдВрд╕реНрдХрд░рдг validString:



рдЕрддреБрд▓реНрдпрдХрд╛рд▓рд┐рдХ "рдкреНрд░рдХрд╛рд╢рдХ" рд╕реЗ "рд╕рджрд╕реНрдпрддрд╛ рд▓реА рдЬрд╛ рд░рд╣реА" рд╣реИ рдХрд┐ рд╣рдо рдореЗрдВ рдмрдирд╛рдП рдЧрдП init( )рд╣реЛ рдЬрд╛рдПрдЧрд╛ рд╡рд░реНрдЧ рдЙрджрд╛рд╣рд░рдг рдХреЗ рдкреВрд░реЗ "рдЬреАрд╡рди рдЪрдХреНрд░" рдкрд░ рдХрд╛рдпрдо рд░рд╣реЗрдВ  ArticlesViewModelErr:



рд╣рдо рдЕрдкрдиреЗ UIрдбреЗрдЯрд╛ рд╕реБрдзрд╛рд░ рдХреА рддреНрд░реБрдЯрд┐рдпреЛрдВ рдХреЗ рд▓рд┐рдП рд╕рдВрднрд╛рд╡рд┐рдд рд░реВрдк рд╕реЗ рдкреНрд░рджрд░реНрд╢рд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЕрдкрдиреЗ рд╕реБрдзрд╛рд░ рдХреЗ рд▓рд┐рдП рдЖрдЧреЗ рдмрдврд╝рддреЗ рд╣реИрдВред рдореЗрдВ SwiftUрдореИрдВ, рдореМрдЬреВрджрд╛ рд╕рдВрд░рдЪрдирд╛ рдореЗрдВ, рд╣рдо  ContentVieArticles  рдПрдХ рдФрд░, рдмрд╕ рдкреНрд░рд╛рдкреНрдд рдХрд╛ рдЙрдкрдпреЛрдЧ  View Model, рдмрд╕ рдкрддреНрд░ "рдЕрд░реЗ" рдирд╛рдо рд╕реЗ рдЬреЛрдбрд╝ рд░рд╣рд╛ рд╣реИред рдпрд╣ рд╡рд░реНрдЧ рдХрд╛ рдПрдХ рдЙрджрд╛рд╣рд░рдг рд╣реИред  ArticlesViewModelErr, рдЬреЛ NewsAPI.org рд╕рд░реНрд╡рд░ рд╕реЗ рд▓реЗрдЦ рдбреЗрдЯрд╛ рдХреЛ рдЪреБрдирдиреЗ рдФрд░ / рдпрд╛ рдбрд┐рдХреЛрдб рдХрд░рдиреЗ рдХреА рддреНрд░реБрдЯрд┐ рдХреЛ "рдкрдХрдбрд╝рддрд╛" рд╣реИ  :



рдФрд░ рд╣рдо Alert рдПрдХ рддреНрд░реБрдЯрд┐ рдХреЗ рдорд╛рдорд▓реЗ рдореЗрдВ рдПрдХ рдЖрдкрд╛рддрдХрд╛рд▓реАрди рд╕рдВрджреЗрд╢ рдХрд╛ рдкреНрд░рджрд░реНрд╢рди рднреА рдЬреЛрдбрд╝рддреЗ рд╣реИрдВ  ред

рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рдпрджрд┐ рдЧрд▓рдд API рдХреБрдВрдЬреА рд╣реИ:

struct APIConstants {
    // News  API key url: https://newsapi.org
    static let apiKey: String = "API_KEY" 
    
   .  .  .  .  .  .  .  .  .  .  .  .  .
}

... рдлрд┐рд░ рд╣рдореЗрдВ рдпрд╣ рд╕рдВрджреЗрд╢ рдорд┐рд▓реЗрдЧрд╛:



рдпрджрд┐ рдЕрдиреБрд░реЛрдзреЛрдВ рдХреА рд╕реАрдорд╛ рд╕рдорд╛рдкреНрдд рд╣реЛ рдЧрдИ рд╣реИ, рддреЛ рд╣рдореЗрдВ рдпрд╣ рд╕рдВрджреЗрд╢ рдорд┐рд▓реЗрдЧрд╛: рд╕рдВрднрд╡ рддреНрд░реБрдЯрд┐ рдХреЗ рд╕рд╛рде 



рд▓реЗрдЦреЛрдВ рдХрд╛ рдЪрдпрди рдХрд░рдиреЗ рдХреА рд╡рд┐рдзрд┐ рдкрд░ рд╡рд╛рдкрд╕ рд▓реМрдЯрдирд╛  , рд╣рдо рдЗрд╕рдХреЗ рдХреЛрдб рдХреЛ рд╕рд░рд▓ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ рдпрджрд┐ рд╣рдо  "рдкреНрд░рдХрд╛рд╢рдХ" рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рд╣реИрдВ  , рдЬреЛ рд╕реЗрдЯ рдХреЗ рдЖрдзрд╛рд░ рдкрд░,  рдЕрддреБрд▓реНрдпрдХрд╛рд▓рд┐рдХ рдЬрд╛рдирдХрд╛рд░реА рдкреНрд░рд╛рдкреНрдд рдХрд░рддрд╛ рд╣реИ, рдЗрд╕реЗ рд╕реАрдзреЗ рд░рдЦрддрд╛ рд╣реИред рдореЗрдВ рдореЙрдбрд▓  рдФрд░ рдПрдХ рддреНрд░реБрдЯрд┐ рд░рд┐рдкреЛрд░реНрдЯ  : рд╣рдо рдЬрд╛рдирддреЗ рд╣реИрдВ, рдЗрд╕ рдХреЛрдб рдХреЛ рдмрд╣реБрдд рд╣реА рдЖрд╕рд╛рди рд╣реИ, рддреЛ рдХреЗ рд▓рд┐рдП рд╕реНрд░реЛрдд рдбреЗрдЯрд╛ рдПрдХ рд╡рд┐рд╢рд┐рд╖реНрдЯ "рдкреНрд░рдХрд╛рд╢рдХ" рдкреНрд░рд╛рдкреНрдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рд╣реИ рдПрдХ рд╣реИ NewsAPI.org рдЦрдмрд░  рдПрдЧреНрд░реАрдЧреЗрдЯрд░  рдпрд╛ рджреЗрд╢ [Article] NewsErrorGenericAnyPublisher<T,NewsError>,urlJSONCodableTNewsError



urlEndpointcountry рд╕реВрдЪрдирд╛ рд╕реНрд░реЛрдд, рдФрд░ рдЖрдЙрдЯрдкреБрдЯ рдХреЗ рд▓рд┐рдП рд╡рд┐рднрд┐рдиреНрди рдореЙрдбрд▓реЛрдВ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реЛрддреА рд╣реИ - рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рд▓реЗрдЦ рдпрд╛ рд╕реВрдЪрдирд╛ рд╕реНрд░реЛрддреЛрдВ рдХреА рдПрдХ рд╕реВрдЪреА:





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


рд╣рдордиреЗ рд╕реАрдЦрд╛ рд╣реИ рдХрд┐рддрдирд╛ рдЖрд╕рд╛рди рд╣реИ рдкреВрд░рд╛ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рд╣реИ HTTPрдХреА рдорджрдж рд╕реЗ рдЕрдиреБрд░реЛрдз Combineрд╣реИ рдЕрдкрдиреЗ URLSession"рдкреНрд░рдХрд╛рд╢рдХ" dataTaskPublisherрдФрд░ Codableред рдпрджрд┐ рдЖрдкрдХреЛ рддреНрд░реБрдЯрд┐рдпреЛрдВ рдХреЛ рдЯреНрд░реИрдХ рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рдирд╣реАрдВ рд╣реИ, рддреЛ рдЖрдкрдХреЛ Generic"рдкреНрд░рдХрд╛рд╢рдХ" рдХреЗ рд▓рд┐рдП рдПрдХ рдмрд╣реБрдд рд╣реА рд╕рд░рд▓ 5-рд▓рд╛рдЗрди рдХреЛрдб AnyPublisher<T, Never>рдкреНрд░рд╛рдкреНрдд рд╣реЛрддрд╛ рд╣реИ, рдЬреЛ рдЕрд╕рд┐рдВрдХреНрд░реЛрдирд╕ рд░реВрдк рд╕реЗ JSON рд╕реВрдЪрдирд╛ рдкреНрд░рд╛рдкреНрдд рдХрд░рддрд╛ рд╣реИ рдФрд░ рдЗрд╕реЗ рд╕реАрдзреЗ  рджрд┐рдП рдЧрдП Codable рдореЙрдбрд▓ рдХреЗ TрдЖрдзрд╛рд░ рдкрд░  рд░рдЦрддрд╛ рд╣реИ url:



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

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



рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ HTTPрдХреНрд╡реЗрд░реА рдирд┐рд╖реНрдкрд╛рджрди рдХреА рддрдХрдиреАрдХ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ Combine, рдЖрдк рдПрдХ "рдкреНрд░рдХрд╛рд╢рдХ" рдмрдирд╛ рд╕рдХрддреЗ рд╣реИрдВ AnyPublisher<UIImage?, Never>рдЬреЛ рдЕрддреБрд▓реНрдпрдХрд╛рд▓рд┐рдХ рд░реВрдк рд╕реЗ рдбреЗрдЯрд╛ рдХрд╛ рдЪрдпрди рдХрд░рддрд╛ рд╣реИ рдФрд░ рдПрдХ UIImage рдЫрд╡рд┐ рдкреНрд░рд╛рдкреНрдд рдХрд░рддрд╛ рд╣реИ? рдХреЗ рдЖрдзрд╛рд░ рдкрд░ URLред ImageLoadeрдмрд╛рд░-рдмрд╛рд░ рдЕрддреБрд▓реНрдпрдХрд╛рд▓рд┐рдХ рдбреЗрдЯрд╛ рдкреБрдирд░реНрдкреНрд░рд╛рдкреНрддрд┐ рд╕реЗ рдмрдЪрдиреЗ рдХреЗ рд▓рд┐рдП рдЫрд╡рд┐ рдбрд╛рдЙрдирд▓реЛрдбрд░ r рдХреЛ рдореЗрдореЛрд░реА рдореЗрдВ рдХреИрд╢ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред

рд╕рднреА рдкреНрд░рдХрд╛рд░ рдХреЗ "рдкрдмреНрд▓рд┐рд╢рд░реНрд╕" рдкреНрд░рд╛рдкреНрдд рдХрд┐рдП рдЬрд╛ рд╕рдХрддреЗ рд╣реИрдВ рдЬрд┐рдиреНрд╣реЗрдВ рдСрдмреНрдЬрд░реНрд╡реЗрдмрд▓рдСрдмреНрдЬреЗрдХреНрдЯ рдХрдХреНрд╖рд╛рдУрдВ рдореЗрдВ "рдХрд╛рдо рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП" рдЖрд╕рд╛рдиреА рд╕реЗ рдмрдирд╛рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ, рдЬреЛ рд╕реНрд╡рд┐рдлреНрдЯрдпреВрдЖрдИ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдЖрдкрдХреЗ рдпреВрдЖрдИ рдХреЛ рдирд┐рдпрдВрддреНрд░рд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЙрдирдХреЗ @ рдЧреБрдгрд┐рдд рдЧреБрдгреЛрдВ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рд╣реИрдВред рдпреЗ рдХрдХреНрд╖рд╛рдПрдВ рдЖрдорддреМрд░ рдкрд░ рджреГрд╢реНрдп рдореЙрдбрд▓ рдХреА рднреВрдорд┐рдХрд╛ рдирд┐рднрд╛рддреА рд╣реИрдВ, рдХреНрдпреЛрдВрдХрд┐ рдЙрдирдХреЗ рдкрд╛рд╕ рддрдерд╛рдХрдерд┐рдд "рдЗрдирдкреБрдЯ" @ рдкреНрд░реЙрдкрд░реНрдЯреАрдЬ рдЧреБрдг рд╣реЛрддреЗ рд╣реИрдВ рдЬреЛ рд╕рдХреНрд░рд┐рдп UI рддрддреНрд╡реЛрдВ (TextField, Stepper, рдкрд┐рдХрд░ рдЯреЗрдХреНрд╕реНрдЯ рдмреЙрдХреНрд╕, рдЯреЙрдЧрд▓ рд░реЗрдбрд┐рдпреЛ рдмрдЯрди, рдЖрджрд┐) рдХреЗ рдЕрдиреБрд░реВрдк рд╣реЛрддреЗ рд╣реИрдВ) рдФрд░ "рдЖрдЙрдЯрдкреБрдЯ рдЖрдЙрдЯрдкреБрдЯ @ рдЧреБрдгрд┐рдд рдЧреБрдг" , рдореБрдЦреНрдп рд░реВрдк рд╕реЗ рдирд┐рд╖реНрдХреНрд░рд┐рдп рдпреВрдЖрдИ рддрддреНрд╡реЛрдВ (рдкрд╛рда, рдЫрд╡рд┐, рдЫрд╡рд┐, рд╕рд░реНрдХрд▓,), рдЖрдпрдд (), рдЖрджрд┐ рд╕реЗ рдорд┐рд▓рдХрд░ ред

рдпрд╣ рд╡рд┐рдЪрд╛рд░ рдЗрд╕ рдЖрд▓реЗрдЦ рдореЗрдВ рдкреНрд░рд╕реНрддреБрдд рдкреВрд░реЗ NewsAPI.org рд╕рдорд╛рдЪрд╛рд░ рдПрдЧреНрд░реАрдЧреЗрдЯрд░ рдЖрд╡реЗрджрди рдХреА рдЕрдиреБрдорддрд┐ рджреЗрддрд╛ рд╣реИред рдХрд╛рдлреА рд╕рд╛рд░реНрд╡рднреМрдорд┐рдХ рдФрд░ рдЬрдм рдЗрд╕реНрддреЗрдорд╛рд▓ рдХрд┐рдпрд╛ рдЧрдпрд╛ рдерд╛TMDb рдореВрд╡реА рдбреЗрдЯрд╛рдмреЗрд╕ рдФрд░ рд╣реИрдХрд░ рд╕рдорд╛рдЪрд╛рд░ рд╕рдорд╛рдЪрд╛рд░ рдПрдЧреНрд░реАрдЧреЗрдЯрд░ рдХреЗ  рд▓рд┐рдП рдПрдХ рдПрдкреНрд▓рд┐рдХреЗрд╢рди рд╡рд┐рдХрд╕рд┐рдд рдХрд░рдирд╛ , рдЬрд┐рд╕ рдкрд░ рднрд╡рд┐рд╖реНрдп рдХреЗ рд▓реЗрдЦреЛрдВ рдореЗрдВ рдЪрд░реНрдЪрд╛ рдХреА рдЬрд╛рдПрдЧреАред

рдЗрд╕ рд▓реЗрдЦ рдХреЗ рд▓рд┐рдП рдЖрд╡реЗрджрди рдХреЛрдб Github рдкрд░ рд╣реИ ред

PS

1. рдореИрдВ рдЗрд╕ рддрдереНрдп рдкрд░ рдЖрдкрдХрд╛ рдзреНрдпрд╛рди рдЖрдХрд░реНрд╖рд┐рдд рдХрд░рдирд╛ рдЪрд╛рд╣рддрд╛ рд╣реВрдВ рдХрд┐ рдпрджрд┐ рдЖрдк рдЗрд╕ рд▓реЗрдЦ рдореЗрдВ рдкреНрд░рд╕реНрддреБрдд рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдХреЗ рд▓рд┐рдП рд╕рд┐рдореНрдпреБрд▓реЗрдЯрд░ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рд╣реИрдВ, рддреЛ рдкрддрд╛ рд╣реИ рдХрд┐ NavigationLinkрд╕рд┐рдореНрдпреБрд▓реЗрдЯрд░ рдПрдХ рддреНрд░реБрдЯрд┐ рдХреЗ рд╕рд╛рде рдХрд╛рдо рдХрд░рддрд╛ рд╣реИред рдЖрдк рдЙрдкрдпреЛрдЧ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВNavigationLinkрд╕рд┐рдореНрдпреБрд▓реЗрдЯрд░ рдкрд░ рдХреЗрд╡рд▓ 1 рдмрд╛рд░ред рдЙрдиред рдЖрдкрдиреЗ рд▓рд┐рдВрдХ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд┐рдпрд╛, рд╡рд╛рдкрд╕ рдЪрд▓рд╛ рдЧрдпрд╛, рдЙрд╕реА рд▓рд┐рдВрдХ рдкрд░ рдХреНрд▓рд┐рдХ рдХрд░реЗрдВ - рдФрд░ рдХреБрдЫ рдирд╣реАрдВ рд╣реЛрддрд╛ рд╣реИред рдЬрдм рддрдХ рдЖрдк рдХрд┐рд╕реА рдЕрдиреНрдп рд▓рд┐рдВрдХ рдХрд╛ рдЙрдкрдпреЛрдЧ рдирд╣реАрдВ рдХрд░рддреЗ, рддрдм рддрдХ рдкрд╣рд▓рд╛ рдХрд╛рдо рдирд╣реАрдВ рдХрд░реЗрдЧрд╛, рд▓реЗрдХрд┐рди рджреВрд╕рд░рд╛ рдЕрдкреНрд░рд╛рдкреНрдп рд╣реЛ рдЬрд╛рдПрдЧрд╛ред рд▓реЗрдХрд┐рди рдпрд╣ рдХреЗрд╡рд▓ рд╕рд┐рдореНрдпреБрд▓реЗрдЯрд░ рдкрд░ рдордирд╛рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ, рдПрдХ рд╡рд╛рд╕реНрддрд╡рд┐рдХ рдбрд┐рд╡рд╛рдЗрд╕ рдкрд░ рд╕рдм рдХреБрдЫ рдареАрдХ рдХрд╛рдо рдХрд░рддрд╛ рд╣реИред

2. рдЬрд╛рдирдХрд╛рд░реА рдХреЗ рдХреБрдЫ рд╕реВрддреНрд░реЛрдВ рдХрд╛ рдХрд╣рдирд╛ рд╣реИ рдЕрднреА рднреА рдЙрдкрдпреЛрдЧ httpрдХреЗ рдмрдЬрд╛рдп httpsрдЕрдкрдиреЗ рд▓реЗрдЦ рдХреЗ "рдЪрд┐рддреНрд░" рдХреЗ рд▓рд┐рдПред рдпрджрд┐ рдЖрдк рдирд┐рд╢реНрдЪрд┐рдд рд░реВрдк рд╕реЗ рдЗрди "рдЪрд┐рддреНрд░реЛрдВ" рдХреЛ рджреЗрдЦрдирд╛ рдЪрд╛рд╣рддреЗ рд╣реИрдВ, рд▓реЗрдХрд┐рди рдЙрдирдХреА рдЙрдкрд╕реНрдерд┐рддрд┐ рдХреЗ рд╕реНрд░реЛрдд рдХреЛ рдирд┐рдпрдВрддреНрд░рд┐рдд рдирд╣реАрдВ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ, рддреЛ рдЖрдкрдХреЛ ATS ( App Transport Security)рдЗрди http"рдЪрд┐рддреНрд░реЛрдВ" рдХреЛ рдкреНрд░рд╛рдкреНрдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рд╕реБрд░рдХреНрд╖рд╛ рдкреНрд░рдгрд╛рд▓реА рдХреЛ рдХреЙрдиреНрдлрд╝рд┐рдЧрд░ рдХрд░рдирд╛ рд╣реЛрдЧрд╛ , рд▓реЗрдХрд┐рди рдпрд╣ рдирд┐рд╢реНрдЪрд┐рдд рд░реВрдк рд╕реЗ, рдПрдХ рдЕрдЪреНрдЫрд╛ рд╡рд┐рдЪрд╛рд░ рдирд╣реАрдВ рд╣реИ ред рдЖрдк рдЕрдзрд┐рдХ рд╕реБрд░рдХреНрд╖рд┐рдд рд╡рд┐рдХрд▓реНрдкреЛрдВ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ ред

рд╕рдВрджрд░реНрдн:


HTTP Swift 5 Combine SwiftUI. 1 .
Modern Networking in Swift 5 with URLSession, Combine and Codable.
URLSession.DataTaskPublisherтАЩs failure type
Combine: Asynchronous Programming with Swift
┬лSwiftUI & Combine: ┬╗
Introducing Combine тАФ WWDC 2019 тАФ Videos тАФ Apple Developer. session 722
( 722 ┬л Combine┬╗ )
Combine in Practice тАФ WWDC 2019 тАФ Videos тАФ Apple Developer. session 721
( 721 ┬л Combine┬╗ )

All Articles