diff --git a/Rick-and-Morty/Rick And Morty.xcodeproj/project.pbxproj b/Rick-and-Morty/Rick And Morty.xcodeproj/project.pbxproj index f29a36f..dc2182e 100644 --- a/Rick-and-Morty/Rick And Morty.xcodeproj/project.pbxproj +++ b/Rick-and-Morty/Rick And Morty.xcodeproj/project.pbxproj @@ -9,6 +9,8 @@ /* Begin PBXBuildFile section */ 1711B39E26B1898100BE935B /* CharacterListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1711B39D26B1898100BE935B /* CharacterListView.swift */; }; 17588BAC26C1750B008ECC31 /* Character.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17588BAB26C1750B008ECC31 /* Character.swift */; }; + 17588BB226C2B126008ECC31 /* RickAndMortyService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17588BB126C2B126008ECC31 /* RickAndMortyService.swift */; }; + 179D2D7626C3D24B008E1B3A /* RickAndMortyServiceProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 179D2D7526C3D24B008E1B3A /* RickAndMortyServiceProtocol.swift */; }; B811686D1CFF1C9900301A0A /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = B811686C1CFF1C9900301A0A /* AppDelegate.swift */; }; B81168761CFF1C9900301A0A /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = B81168751CFF1C9900301A0A /* Assets.xcassets */; }; B81168791CFF1C9900301A0A /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = B81168771CFF1C9900301A0A /* LaunchScreen.storyboard */; }; @@ -28,6 +30,8 @@ /* Begin PBXFileReference section */ 1711B39D26B1898100BE935B /* CharacterListView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CharacterListView.swift; sourceTree = ""; }; 17588BAB26C1750B008ECC31 /* Character.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Character.swift; sourceTree = ""; }; + 17588BB126C2B126008ECC31 /* RickAndMortyService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RickAndMortyService.swift; sourceTree = ""; }; + 179D2D7526C3D24B008E1B3A /* RickAndMortyServiceProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RickAndMortyServiceProtocol.swift; sourceTree = ""; }; B81168691CFF1C9900301A0A /* Rick And Morty.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Rick And Morty.app"; sourceTree = BUILT_PRODUCTS_DIR; }; B811686C1CFF1C9900301A0A /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; B81168751CFF1C9900301A0A /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; @@ -64,6 +68,15 @@ path = Model; sourceTree = ""; }; + 17588BB026C2B112008ECC31 /* Services */ = { + isa = PBXGroup; + children = ( + 17588BB126C2B126008ECC31 /* RickAndMortyService.swift */, + 179D2D7526C3D24B008E1B3A /* RickAndMortyServiceProtocol.swift */, + ); + path = Services; + sourceTree = ""; + }; B81168601CFF1C9900301A0A = { isa = PBXGroup; children = ( @@ -85,6 +98,7 @@ B811686B1CFF1C9900301A0A /* Rick And Morty */ = { isa = PBXGroup; children = ( + 17588BB026C2B112008ECC31 /* Services */, 17588BAA26C174FB008ECC31 /* Model */, B811686C1CFF1C9900301A0A /* AppDelegate.swift */, 1711B39D26B1898100BE935B /* CharacterListView.swift */, @@ -208,7 +222,9 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 17588BB226C2B126008ECC31 /* RickAndMortyService.swift in Sources */, 17588BAC26C1750B008ECC31 /* Character.swift in Sources */, + 179D2D7626C3D24B008E1B3A /* RickAndMortyServiceProtocol.swift in Sources */, 1711B39E26B1898100BE935B /* CharacterListView.swift in Sources */, B811686D1CFF1C9900301A0A /* AppDelegate.swift in Sources */, ); diff --git a/Rick-and-Morty/Rick And Morty/Model/Character.swift b/Rick-and-Morty/Rick And Morty/Model/Character.swift index e755913..be23f82 100644 --- a/Rick-and-Morty/Rick And Morty/Model/Character.swift +++ b/Rick-and-Morty/Rick And Morty/Model/Character.swift @@ -8,6 +8,19 @@ import Foundation + +struct CharactersList: Decodable { + let info: CharacterListInfo + let results: [Character] +} + +struct CharacterListInfo: Decodable { + let count: Int + let next: String? + let pages: Int + let prev: String? +} + struct Character: Decodable { let id: Int let name: String diff --git a/Rick-and-Morty/Rick And Morty/Services/RickAndMortyService.swift b/Rick-and-Morty/Rick And Morty/Services/RickAndMortyService.swift new file mode 100644 index 0000000..904e748 --- /dev/null +++ b/Rick-and-Morty/Rick And Morty/Services/RickAndMortyService.swift @@ -0,0 +1,44 @@ +// +// RickAndMortyService.swift +// Rick And Morty +// +// Created by Scottie Gray on 2021-08-10. +// Copyright © 2021 Novoda. All rights reserved. +// + +import Foundation + +final class RickAndMortyService: RickAndMortyServiceProtocol { + static let baseURL = URL(string: "https://rickandmortyapi.com/api")! + + func fetchData(url: URL, success: @escaping (T) -> (), error: @escaping (Error?) -> ()) { + let request = URLRequest(url: url) + + URLSession.shared.dataTask(with: request) { data, response, requestError in + if requestError != nil { + DispatchQueue.main.async { + error(requestError) + } + } + + if let data = data { + let decoder = JSONDecoder() + + do { + let decodedData = try decoder.decode(T.self, from: data) + DispatchQueue.main.async { + success(decodedData) + } + } catch let decodingError { + DispatchQueue.main.async { + error(decodingError) + } + } + } else { + DispatchQueue.main.async { + error(requestError) + } + } + }.resume() + } +} diff --git a/Rick-and-Morty/Rick And Morty/Services/RickAndMortyServiceProtocol.swift b/Rick-and-Morty/Rick And Morty/Services/RickAndMortyServiceProtocol.swift new file mode 100644 index 0000000..e8fbc61 --- /dev/null +++ b/Rick-and-Morty/Rick And Morty/Services/RickAndMortyServiceProtocol.swift @@ -0,0 +1,13 @@ +// +// RickAndMortyServiceProtocol.swift +// Rick And Morty +// +// Created by Scottie Gray on 2021-08-11. +// Copyright © 2021 Novoda. All rights reserved. +// + +import Foundation + +protocol RickAndMortyServiceProtocol { + func fetchData(url: URL, success: @escaping (T) -> (), error: @escaping (Error?) -> ()) +}