рдХреНрд╡реЗрд░реА HTTP
рдЖрдк рдЬрдм рд╡рд┐рдХрд╛рд╕рд╢реАрд▓ рдкреНрд░рд╛рдкреНрдд рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╕рдмрд╕реЗ рдорд╣рддреНрд╡рдкреВрд░реНрдг рдХреМрд╢рд▓ рдореЗрдВ рд╕реЗ рдПрдХ рд╣реИ iOS
рдЕрдиреБрдкреНрд░рдпреЛрдЧреЛрдВред рдкрд╣рд▓реЗ рдХреЗ рд╕рдВрд╕реНрдХрд░рдгреЛрдВ рдореЗрдВ Swift
(рд╕рдВрд╕реНрдХрд░рдг 5 рд╕реЗ рдкрд╣рд▓реЗ), рднрд▓реЗ рд╣реА рдЖрдкрдиреЗ рд╕реНрдХреНрд░реИрдЪ рд╕реЗ рдЗрди рдЕрдиреБрд░реЛрдзреЛрдВ рдХреЛ рдЙрддреНрдкрдиреНрди рдХрд┐рдпрд╛ рд╣реЛ рдпрд╛ рдЕрдЪреНрдЫреА рддрд░рд╣ рд╕реЗ рдЬреНрдЮрд╛рдд рдЕрд▓реНрдореЛрдлрд╛рдпрд░ рдлреНрд░реЗрдорд╡рд░реНрдХ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ , рдЖрдкрдиреЗ рдЬрдЯрд┐рд▓ рдФрд░ рднреНрд░рдорд┐рдд рдХреЛрдб рдХреЛ callback
рдкреНрд░рдХрд╛рд░ рд╕реЗ рд╕рдорд╛рдкреНрдд рдХрд░ рджрд┐рдпрд╛ completionHandler: @escaping(Result<T, APIError>) -> Void
ред рдореМрдЬреВрджрд╛ рдХреЗ рд╕рд╛рде рд╕рдВрдпреЛрдЬрди рдХреЗ рд░реВрдк рдореЗрдВ рдХрд╛рд░реНрдпрд╛рддреНрдордХ рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛рд╢реАрд▓ рдкреНрд░реЛрдЧреНрд░рд╛рдорд┐рдВрдЧ рдХреЗ рдирдП рдврд╛рдВрдЪреЗрдореЗрдВ рдЙрдкрд╕реНрдерд┐рддрд┐ , рдФрд░ рдЖрдкрдХреЛ рдЗрдВрдЯрд░рдиреЗрдЯ рд╕реЗ рдбреЗрдЯрд╛ рдкреНрд░рд╛рдкреНрдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдмрд╣реБрдд рдХреЙрдореНрдкреИрдХреНрдЯ рдХреЛрдб рд╕реНрд╡рддрдВрддреНрд░ рд▓реЗрдЦрди рдХреЗ рд▓рд┐рдП рдЖрд╡рд╢реНрдпрдХ рд╕рднреА рдЙрдкрдХрд░рдг рдкреНрд░рджрд╛рди рдХрд░рддрд╛ рд╣реИред рдЗрд╕ рд▓реЗрдЦ рдореЗрдВ, рдЕрд╡рдзрд╛рд░рдгрд╛ рдХреЗ рдЕрдиреБрд╕рд╛рд░, рд╣рдо "рдкреНрд░рдХрд╛рд╢рдХ" рдмрдирд╛рдПрдВрдЧреЗSwift 5
Combine
URLSession
Codable
Combine
Publisher
рдЗрдВрдЯрд░рдиреЗрдЯ рд╕реЗ рдбреЗрдЯрд╛ рдХрд╛ рдЪрдпрди рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рдЬрд┐рд╕реЗ рд╣рдо рднрд╡рд┐рд╖реНрдп рдореЗрдВ рдЖрд╕рд╛рдиреА рд╕реЗ "рд╕рдмреНрд╕рдХреНрд░рд╛рдЗрдм" рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ рдФрд░ рдЙрдкрдпреЛрдЧ рдХреЗ UI
рд╕рд╛рде UIKit
рдФрд░ рд╕рд╣рд╛рдпрддрд╛ рдХреЗ рд╕рд╛рде рдбрд┐рдЬрд╝рд╛рдЗрди рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ SwiftUI
редрдЬреИрд╕рд╛ рдХрд┐ SwiftUI
рдпрд╣ рдЕрдзрд┐рдХ рд╕рдВрдХреНрд╖рд┐рдкреНрдд рдФрд░ рдЕрдзрд┐рдХ рдкреНрд░рднрд╛рд╡реА рдврдВрдЧ рд╕реЗ рджрд┐рдЦрддрд╛ рд╣реИ, рдХреНрдпреЛрдВрдХрд┐ "рдкреНрд░рдХрд╛рд╢рдХреЛрдВ" рдХреА рдХрд╛рд░реНрд░рд╡рд╛рдИ Publisher
рдХреЗрд╡рд▓ рдирдореВрдирд╛ рдбреЗрдЯрд╛ рддрдХ рд╕реАрдорд┐рдд рдирд╣реАрдВ рд╣реИ, рдФрд░ рдЖрдЧреЗ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдЗрдВрдЯрд░рдлрд╝реЗрд╕ рдирд┐рдпрдВрддреНрд░рдг ( UI
) рддрдХ рдлреИрд▓реА рд╣реБрдИ рд╣реИ ред рддрдереНрдп рдпрд╣ рд╣реИ рдХрд┐ рдЧреБрдгреЛрдВ рдХреЗ рд╕рд╛рде рдХрдХреНрд╖рд╛рдУрдВ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ SwiftUI
рдбреЗрдЯрд╛ рдкреГрдердХреНрдХрд░рдг View
рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ , рдЬрд┐рдирдореЗрдВ рд╕реЗ рдкрд░рд┐рд╡рд░реНрддрди рд╕реНрд╡рдЪрд╛рд▓рд┐рдд рд░реВрдк рд╕реЗ рдЯреНрд░реИрдХ рдХрд░рддреЗ рд╣реИрдВ рдФрд░ рдкреВрд░реА рддрд░рд╣ рд╕реЗ "рд░рд┐рдбреНрд░рд╛" рдЕрдкрдиреЗ рд╕реНрд╡рдпрдВ рдХреЗ рд╣реЛрддреЗ рд╣реИрдВ ред рдЗрди рд╡рд░реНрдЧреЛрдВ рдореЗрдВ, рдЖрдк рдмрд╣реБрдд рд╣реА рд╕рд░рд▓рддрд╛ рд╕реЗ рдЖрд╡реЗрджрди рдХреЗ рдПрдХ рдирд┐рд╢реНрдЪрд┐рдд рд╡реНрдпрд╛рд╡рд╕рд╛рдпрд┐рдХ рддрд░реНрдХ рдХреЛ рд░рдЦ рд╕рдХрддреЗ рд╣реИрдВ, рдпрджрд┐ рдЗрдирдореЗрдВ рд╕реЗ рдХреБрдЫObservableObject
@Published
SwiftUI
View
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 рд╕рдорд╛рдЪрд╛рд░ рдПрдЧреНрд░реАрдЧреЗрдЯрд░ рд╕реЗ рдбреЗрдЯрд╛ рдХреЗ рдЪрдпрди рдХреЗ рд▓рд┐рдП рджреЛ рддрд░реАрдХреЗ рдкреНрд░рд╕реНрддреБрдд рдХрд░рддрд╛ рд╣реИ - рд▓реЗрдЦ рдФрд░ рд╕реВрдЪрдирд╛ рд╕реНрд░реЛрдд :API
NewsAPI
[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 {
return Just([Article]()).eraseToAnyPublisher()
}
return
URLSession.shared.dataTaskPublisher(for:url)
.map{$0.data}
.decode(type: NewsResponse.self,
decoder: APIConstants .jsonDecoder)
.map{$0.articles}
.replaceError(with: [])
.receive(on: RunLoop.main)
.eraseToAnyPublisher()
}
- рд▓реЗрдЦреЛрдВ рдХреА рд╡рд╛рдВрдЫрд┐рдд рд╕реВрдЪреА рдХреЗ рдЕрдиреБрд░реЛрдз рдХреЗ рд▓рд┐рдП
endpoint
рдлреЙрд░реНрдо рдХреЗ рдЖрдзрд╛рд░ рдкрд░ , рдпрджрд┐ рдРрд╕рд╛ рдирд╣реАрдВ рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ, рддреЛ рд▓реЗрдЦреЛрдВ рдХреА рдПрдХ рдЦрд╛рд▓реА рд╕рд░рдгреА рд▓реМрдЯрд╛рдПрдВURL
endpoint.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 {
return Just([Source]()).eraseToAnyPublisher()
}
return
URLSession.shared.dataTaskPublisher(for:url)
.map{$0.data}
.decode(type: SourcesResponse.self,
decoder: APIConstants .jsonDecoder)
.map{$0.sources}
.replaceError(with: [])
.receive(on: RunLoop.main)
.eraseToAnyPublisher()
}
рдпрд╣ AnyPublisher <[Source], Never>
рд╕реВрдЪрдирд╛ рд╕реНрд░реЛрддреЛрдВ рдХреА рдПрдХ рд╕рд░рдгреА рдХреЗ рд░реВрдк рдореЗрдВ [Source]
рдФрд░ рддреНрд░реБрдЯрд┐ рдХреА рдЕрдиреБрдкрд╕реНрдерд┐рддрд┐ Never
(рддреНрд░реБрдЯрд┐рдпреЛрдВ рдХреЗ рдорд╛рдорд▓реЗ рдореЗрдВ, рд╕реВрддреНрд░реЛрдВ рдХрд╛ рдПрдХ рдЦрд╛рд▓реА рд╕рд░рдгреА рд▓реМрдЯрд╛рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ [ ]
) рдХреЗ рд░реВрдк рдореЗрдВ рдПрдХ рдореВрд▓реНрдп рдХреЗ рд╕рд╛рде "рдкреНрд░рдХрд╛рд╢рдХ" рд╣рдорд╛рд░реЗ рдкрд╛рд╕ рд▓реМрдЯрддрд╛ рд╣реИ редрд╣рдо рдЗрди рджреЛрдиреЛрдВ рд╡рд┐рдзрд┐рдпреЛрдВ рдХреЗ рд╕рд╛рдорд╛рдиреНрдп рднрд╛рдЧ рдХреЛ рд╕рд┐рдВрдЧрд▓ рдХрд░ рджреЗрдВрдЧреЗ, рдЗрд╕реЗ рдПрдХ Generic
рдлрдВрдХреНрд╢рди рдХреЗ рд░реВрдк рдореЗрдВ рд╡реНрдпрд╡рд╕реНрдерд┐рдд рдХрд░реЗрдВрдЧреЗ, fetch(_ url: URL) -> AnyPublisher<T, Error>
рдЬреЛ Generic
"рдкреНрд░рдХрд╛рд╢рдХ" AnyPublisher<T, Error>
рдкрд░ рдЖрдзрд╛рд░рд┐рдд рд╣реИ URL
:
func fetch<T: Decodable>(_ url: URL) -> AnyPublisher<T, Error> {
URLSession.shared.dataTaskPublisher(for: url)
.map { $0.data}
.decode(type: T.self, decoder: APIConstants.jsonDecoder)
.receive(on: RunLoop.main)
.eraseToAnyPublisher()
}
рдпрд╣ рдкрд┐рдЫрд▓реЗ рджреЛ рддрд░реАрдХреЛрдВ рдХреЛ рд╕рд░рд▓ рдХрд░реЗрдЧрд╛:
func fetchArticles(from endpoint: Endpoint)
-> AnyPublisher<[Article], Never> {
guard let url = endpoint.absoluteURL else {
return Just([Article]()).eraseToAnyPublisher()
}
return fetch(url)
.map { (response: NewsResponse) -> [Article] in
return response.articles }
.replaceError(with: [Article]())
.eraseToAnyPublisher()
}
func fetchSources(for country: String)
-> AnyPublisher<[Source], Never> {
guard let url = Endpoint.sources(country: country).absoluteURL
else {
return Just([Source]()).eraseToAnyPublisher()
}
return fetch(url)
.map { (response: SourcesResponse) -> [Source] in
response.sources }
.replaceError(with: [Source]())
.eraseToAnyPublisher()
}
рдЗрд╕ рдкреНрд░рдХрд╛рд░ рдкреНрд░рд╛рдкреНрдд "рдкреНрд░рдХрд╛рд╢рдХ" рддрдм рддрдХ рдХреБрдЫ рдирд╣реАрдВ рджреЗрддреЗ рдЬрдм рддрдХ рдХрд┐ рдХреЛрдИ рд╡реНрдпрдХреНрддрд┐ рдЙрдирдХреА "рд╕рджрд╕реНрдпрддрд╛" рди рд▓реЗ рд▓реЗред рд╣рдо рдпрд╣ рддрдм рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ рдЬрдм рдбрд┐рдЬрд╛рдЗрдирд┐рдВрдЧ 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
рд▓реЗрдЦреЛрдВ рдХреА рд╕реВрдЪреА рдХреА рдирд┐рд░реНрднрд░рддрд╛ рдХреЛ рдкреБрди: рдЙрддреНрдкрдиреНрди рдХрд░реЗрдЧрд╛ ред рдРрд╕рд╛ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рд╣рдо "рдкреНрд░рдХрд╛рд╢рдХреЛрдВ" рдХреА рд╢реНрд░реГрдВрдЦрд▓рд╛ рдХрд╛ рд╡рд┐рд╕реНрддрд╛рд░ рдФрд░ рдЙрддреНрдкрд╛рджрди "рдкреНрд░рдХрд╛рд╢рдХ" рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдПarticles
indexEndpoint
searchString
Combine
$indexEndpoint
$searchString
AnyPublisher<[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
рд╕реЗрд╡ рдХрд░реЗрдЧрд╛ ред AnyCancellable
ArticlesViewMode
рдЗрд╕рд▓рд┐рдП, рд╣рдо рдирд┐рд░рдВрддрд░ рдХреЛ рд╣рдЯрд╛рддреЗ рд╣реИрдВ 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 articleViewModel
Text ("Hello, World!")
ArticlesList
articlesViewModel.articles
View Model
ред рдирддреАрдЬрддрди, рд╣рдореЗрдВ рдПрдХ рдирд┐рд╢реНрдЪрд┐рдд рдФрд░ рдбрд┐рдлрд╝реЙрд▓реНрдЯ рд╕реВрдЪрдХрд╛рдВрдХ рдХреЗ рд▓рд┐рдП рд▓реЗрдЦреЛрдВ рдХреА рдПрдХ рд╕реВрдЪреА рдорд┐рд▓рддреА рд╣реИ indexEndpoint = 0
, рдЬреЛ рдХрд┐ .topHeadLines
рдирд╡реАрдирддрдо рд╕рдорд╛рдЪрд╛рд░реЛрдВ рдХреЗ рд▓рд┐рдП рд╣реИ:
рд╣рдорд╛рд░реЗ рд╕реНрдХреНрд░реАрди UI
рдкрд░ рдПрдХ рддрддреНрд╡ рдЬреЛрдбрд╝реЗрдВ рдЬреЛ рд▓реЗрдЦреЛрдВ рдХреЗ рд╕реЗрдЯ рдХреЛ рдкреНрд░рджрд░реНрд╢рд┐рдд рдХрд░рдирд╛ рдЪрд╛рд╣рддреЗ рд╣реИрдВред рд╣рдо Picker
рд╕реВрдЪрдХрд╛рдВрдХ рдкрд░рд┐рд╡рд░реНрддрди рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░реЗрдВрдЧреЗ $articlesViewModel.indexEndpoint
ред рдПрдХ рдкреНрд░рддреАрдХ рдХреА рдЙрдкрд╕реНрдерд┐рддрд┐ $
рдЕрдирд┐рд╡рд╛рд░реНрдп рд╣реИ, рдХреНрдпреЛрдВрдХрд┐ рдЗрд╕рдХрд╛ рдорддрд▓рдм @Published
"рдкреНрд░рдХрд╛рд╢рдХ" рджреНрд╡рд╛рд░рд╛ рдЖрдкреВрд░реНрддрд┐ рдХрд┐рдП рдЧрдП рдореВрд▓реНрдп рдореЗрдВ рдмрджрд▓рд╛рд╡ рд╣реИ ред рдЗрд╕ "рдкреНрд░рдХрд╛рд╢рдХ" рдХреЗ рд▓рд┐рдП "рд╕рджрд╕реНрдпрддрд╛" рддреБрд░рдВрдд рд╢реБрд░реВ рд╣реЛ рдЬрд╛рддреА рд╣реИ, рдЬрд┐рд╕ рдкрд░ рд╣рдордиреЗ рд╢реБрд░реБрдЖрдд рдХреА init ()
, "рдЖрдЙрдЯрдкреБрдЯ" @Published
"рдкреНрд░рдХрд╛рд╢рдХ" articles
рдмрджрд▓ рдЬрд╛рдПрдЧрд╛ рдФрд░ рд╣рдо рд╕реНрдХреНрд░реАрди рдкрд░ рд▓реЗрдЦреЛрдВ рдХреА рдПрдХ рдЕрд▓рдЧ рд╕реВрдЪреА рджреЗрдЦреЗрдВрдЧреЗ:
рдЗрд╕ рддрд░рд╣ рд╣рдо рддреАрди рд╡рд┐рдХрд▓реНрдкреЛрдВ рдХреЗ рд▓рд┐рдП рд▓реЗрдЦреЛрдВ рдХреЗ рд╕рд░рдгрд┐рдпреЛрдВ рдХреЛ рдкреНрд░рд╛рдкреНрдд рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ - "рдЯреЙрдкрд╣реЗрдбрд▓рд╛рдЗрди", "рдЦреЛрдЬ "рдФрд░" рд╢реНрд░реЗрдгреА рд╕реЗ ":
... рд▓реЗрдХрд┐рди рдПрдХ рдирд┐рд╢реНрдЪрд┐рдд рдФрд░ рдбрд┐рдлрд╝реЙрд▓реНрдЯ рдЦреЛрдЬ рд╕реНрдЯреНрд░рд┐рдВрдЧ рдХреЗ рд▓рд┐рдП searchString = "sports"
(рдЬрд╣рд╛рдВ рдЗрд╕рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реЛрддреА рд╣реИ):
рд╣рд╛рд▓рд╛рдВрдХрд┐, рд╡рд┐рдХрд▓реНрдк рдХреЗ рд▓рд┐рдП, "search"
рдЖрдкрдХреЛ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ SearchView
рдХреЛ рдЦреЛрдЬ рд╕реНрдЯреНрд░рд┐рдВрдЧ рджрд░реНрдЬ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдПрдХ рдкрд╛рда рдлрд╝реАрд▓реНрдб рдкреНрд░рджрд╛рди рдХрд░рдирд╛ рд╣реЛрдЧрд╛ :
рдкрд░рд┐рдгрд╛рдорд╕реНрд╡рд░реВрдк, рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдЯрд╛рдЗрдк рдХрд┐рдП рдЧрдП рдЦреЛрдЬ рд╕реНрдЯреНрд░рд┐рдВрдЧ рджреНрд╡рд╛рд░рд╛ рдХрд┐рд╕реА рднреА рд╕рдорд╛рдЪрд╛рд░ рдХреЛ рдЦреЛрдЬ рд╕рдХрддрд╛ рд╣реИ:
рд╡рд┐рдХрд▓реНрдк рдХреЗ рд▓рд┐рдП, "from category"
рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдХреЛ рдкреНрд░рджрд╛рди рдХрд░рдирд╛ рдЖрд╡рд╢реНрдпрдХ рд╣реИ рдЕрд╡рд╕рд░ рдПрдХ рд╡рд░реНрдЧ рдХрд╛ рдЪрдпрди рдХрд░рдиреЗ рдФрд░ рд╣рдо рд╢реНрд░реЗрдгреА рдХреЗ рд╕рд╛рде рд╢реБрд░реВ science
:
рдПрдХ рдкрд░рд┐рдгрд╛рдо рдХреЗ рд░реВрдк, рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдЦрдмрд░ рдХреЗ рдЪрдпрдирд┐рдд рд╢реНрд░реЗрдгреА рдкрд░ рдХрд┐рд╕реА рднреА рдЦрдмрд░ рдХреЗ рд▓рд┐рдП рдЦреЛрдЬ рд╕рдХрддреЗ рд╣реИрдВ - science
, health
, business
, 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
UI
SwiftUI
View
ObservableObject
рдореЙрдбрд▓ рдПрдХ @ObservedObject
рдЪрд░ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддрд╛ рд╣реИ рдЬреЛ рдЗрд╕ рдореЙрдбрд▓ рдХреЗ рд╡рд░реНрдЧ рдХреА рдПрдХ рдЖрд╡реГрддреНрддрд┐ рдХреЛ рд╕рдВрджрд░реНрднрд┐рдд рдХрд░рддрд╛ рд╣реИред рдПрдХ рдЪрд░ рдХреЗ рд░реВрдк рдореЗрдВрд╕рдВрд░рдЪрдирд╛ рдореЗрдВ ContentViewSources
рд╡рд░реНрдЧ рдЙрджрд╛рд╣рд░рдг рдЬреЛрдбрд╝реЗрдВ , рдкреНрд░рддреНрдпреЗрдХ 3 рдЧреБрдгреЛрдВ рдХреЗ рд▓рд┐рдП рдЕрдкрдирд╛ рд╕реНрд╡рдпрдВ рдХрд╛ рд╕реНрдерд╛рди рдирд┐рдХрд╛рд▓реЗрдВ рдФрд░ рд░рдЦреЗрдВ :SourcesViewModel
var sourcesViewModel
Text ("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
nil
UIImage?
UI
fetchImage(for url: URL?)
url
рдЖрдЗрдП рд╡рд┐рд╕реНрддрд╛рд░ рд╕реЗ рд╡рд┐рдЪрд╛рд░ рдХрд░реЗрдВ рдХрд┐ Combine
"рдкреНрд░рдХрд╛рд╢рдХ" рдХреА рдорджрдж рд╕реЗ рдЧрдарди рдХреИрд╕реЗ рдЪрд▓ рд░рд╣рд╛ рд╣реИ AnyPublisher <UIImage?, Never>
, рдЕрдЧрд░ рд╣рдо рдЬрд╛рдирддреЗ рд╣реИрдВ url
:- рдЕрдЧрд░
url
рдмрд░рд╛рдмрд░ рд╣реИ nil
, рд▓реМрдЯрд╛рдУ Just(nil)
, - рдХреЗ рдЖрдзрд╛рд░ рдкрд░
url
"рдкреНрд░рдХрд╛рд╢рдХ" рдХреЗ рд░реВрдк dataTaskPublisher(for:)
рд╣реИ, рдЬрд┐рд╕рдХрд╛ рдЙрддреНрдкрд╛рджрди рдореВрд▓реНрдп Output
рдПрдХ рдЯрдкрд▓ рд╣реИ (data: Data, response: URLResponse)
рдФрд░ рдПрдХ рддреНрд░реБрдЯрд┐ Failure
- URLError
, - рд╣рдо рдЖрдЧреЗ рдХреА рдкреНрд░рдХреНрд░рд┐рдпрд╛ рдФрд░ рдлрд╝реЙрд░реНрдо рдХреЗ рд▓рд┐рдП рдХреЗрд╡рд▓
map {}
рдЯрдкрд▓ рд╕реЗ (data: Data, response: URLResponse)
рдбреЗрдЯрд╛ рд▓реЗрддреЗ рд╣реИрдВ ,data
UIImage
- рдпрджрд┐ рдкрд┐рдЫрд▓реЗ рдЪрд░рдг рд╡рд╛рдкрд╕реА рддреНрд░реБрдЯрд┐ рд╣реЛрддреА рд╣реИ
nil
, - рд╣рдо
main
рд╕реНрдЯреНрд░реАрдо рдХреЛ рдкрд░рд┐рдгрд╛рдо рджреЗрддреЗ рд╣реИрдВ, рдЬреИрд╕рд╛ рдХрд┐ рд╣рдо рдбрд┐рдЬрд╝рд╛рдЗрди рдореЗрдВ рдЖрдЧреЗ рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рд╣реИрдВ UI
, - "рдкреНрд░рдХрд╛рд╢рдХ" рдХреЗ рдкреНрд░рдХрд╛рд░ "рдорд┐рдЯрд╛" рдФрд░ рдкреНрд░рддрд┐рд▓рд┐рдкрд┐ рд╡рд╛рдкрд╕ рдХрд░реЗрдВ
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
рд╕рдВрдЧреНрд░рд╣реАрдд рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ ред рдЗрд╕ "рдЫрд╡рд┐ рдбрд╛рдЙрдирд▓реЛрдбрд░" рдХрд╛ рддрд░реНрдХ рдпрд╣ рд╣реИ рдХрд┐ рдЖрдк рдПрдХ рдЫрд╡рд┐ рдХреЛ рдХрд┐рд╕реА рдЕрдиреНрдп рдЪреАрдЬрд╝ рд╕реЗ рдбрд╛рдЙрдирд▓реЛрдб рдХрд░рддреЗ рд╣реИрдВ, рдмрд╢рд░реНрддреЗ рдХрд┐ рд╡рд╣ рдкреНрд░реАрд▓реЛрдб рди рд╣реЛ, рдЬреЛ рд╣реИAnyCancellable
store(in: &self.cancellableSet)
nil URL
image == 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>
url
fetchImageErr (for url: URL?)

fetchImageErr
Future
Result
Promise
(Result<Output, Failure>) тЖТ Void

Future
AnyPublisher <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:)
рдПрдХ рддреНрд░реБрдЯрд┐ рджреЗрддрд╛ рд╣реИ ред рдпрджрд┐ рд╣рдо рддреНрд░реБрдЯрд┐рдпреЛрдВ рдХреЛ рдкреНрд░рджрд░реНрд╢рд┐рдд рдХрд░рдирд╛ рдЪрд╛рд╣рддреЗ рд╣реИрдВ , рддреЛ рд╣рдореЗрдВ рдЙрд╕реА рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ , рдЬрд┐рд╕реЗ рд╣рдо рдХрд╣реЗрдВрдЧреЗ : рдкреНрд░реЛрдЯреЛрдХреЙрд▓ рд▓рд╛рдЧреВ рдХрд░рдиреЗ рд╡рд╛рд▓реЗ рд╡рд░реНрдЧ рдореЗрдВ , рдЗрд╕ рдмрд╛рд░ рд╣рдорд╛рд░реЗ рдкрд╛рд╕ рдЧреБрдг рд╣реИрдВ:URLError
ATS
SwiftUI
View Model
ArticlesViewModelErr

ArticlesViewModelErr
ObservableObject
@Published
@Published var indexEndpoint: Int
тАФ Endpoint
( ┬л┬╗, View
), @Published var searchString: String
тАФ , Endpoint
: ┬л┬╗ , ( ┬л┬╗, View
), -
@Published var articles: [Article]
- ( ┬л┬╗, NewsAPI.org ) -
@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 {
static let apiKey: String = "API_KEY"
. . . . . . . . . . . . .
}
... рдлрд┐рд░ рд╣рдореЗрдВ рдпрд╣ рд╕рдВрджреЗрд╢ рдорд┐рд▓реЗрдЧрд╛:
рдпрджрд┐ рдЕрдиреБрд░реЛрдзреЛрдВ рдХреА рд╕реАрдорд╛ рд╕рдорд╛рдкреНрдд рд╣реЛ рдЧрдИ рд╣реИ, рддреЛ рд╣рдореЗрдВ рдпрд╣ рд╕рдВрджреЗрд╢ рдорд┐рд▓реЗрдЧрд╛: рд╕рдВрднрд╡ рддреНрд░реБрдЯрд┐ рдХреЗ рд╕рд╛рде
рд▓реЗрдЦреЛрдВ рдХрд╛ рдЪрдпрди рдХрд░рдиреЗ рдХреА рд╡рд┐рдзрд┐ рдкрд░ рд╡рд╛рдкрд╕ рд▓реМрдЯрдирд╛ , рд╣рдо рдЗрд╕рдХреЗ рдХреЛрдб рдХреЛ рд╕рд░рд▓ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ рдпрджрд┐ рд╣рдо "рдкреНрд░рдХрд╛рд╢рдХ" рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рд╣реИрдВ , рдЬреЛ рд╕реЗрдЯ рдХреЗ рдЖрдзрд╛рд░ рдкрд░, рдЕрддреБрд▓реНрдпрдХрд╛рд▓рд┐рдХ рдЬрд╛рдирдХрд╛рд░реА рдкреНрд░рд╛рдкреНрдд рдХрд░рддрд╛ рд╣реИ, рдЗрд╕реЗ рд╕реАрдзреЗ рд░рдЦрддрд╛ рд╣реИред рдореЗрдВ рдореЙрдбрд▓ рдФрд░ рдПрдХ рддреНрд░реБрдЯрд┐ рд░рд┐рдкреЛрд░реНрдЯ : рд╣рдо рдЬрд╛рдирддреЗ рд╣реИрдВ, рдЗрд╕ рдХреЛрдб рдХреЛ рдмрд╣реБрдд рд╣реА рдЖрд╕рд╛рди рд╣реИ, рддреЛ рдХреЗ рд▓рд┐рдП рд╕реНрд░реЛрдд рдбреЗрдЯрд╛ рдПрдХ рд╡рд┐рд╢рд┐рд╖реНрдЯ "рдкреНрд░рдХрд╛рд╢рдХ" рдкреНрд░рд╛рдкреНрдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рд╣реИ рдПрдХ рд╣реИ NewsAPI.org рдЦрдмрд░ рдПрдЧреНрд░реАрдЧреЗрдЯрд░ рдпрд╛ рджреЗрд╢ [Article]
NewsError
Generic
AnyPublisher<T,NewsError>,
url
JSON
Codable
T
NewsError

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

рдирд┐рд╖реНрдХрд░реНрд╖
рд╣рдордиреЗ рд╕реАрдЦрд╛ рд╣реИ рдХрд┐рддрдирд╛ рдЖрд╕рд╛рди рд╣реИ рдкреВрд░рд╛ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рд╣реИ 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 рдкрд░ рд╣реИ редPS1. рдореИрдВ рдЗрд╕ рддрдереНрдп рдкрд░ рдЖрдкрдХрд╛ рдзреНрдпрд╛рди рдЖрдХрд░реНрд╖рд┐рдд рдХрд░рдирд╛ рдЪрд╛рд╣рддрд╛ рд╣реВрдВ рдХрд┐ рдпрджрд┐ рдЖрдк рдЗрд╕ рд▓реЗрдЦ рдореЗрдВ рдкреНрд░рд╕реНрддреБрдд рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдХреЗ рд▓рд┐рдП рд╕рд┐рдореНрдпреБрд▓реЗрдЯрд░ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рд╣реИрдВ, рддреЛ рдкрддрд╛ рд╣реИ рдХрд┐ 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 typeCombine: 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┬╗ )