From 1752ea7075939fb49dd72e0b8ea2accc2be1b02a Mon Sep 17 00:00:00 2001 From: Nicholas Tay Date: Fri, 25 Mar 2022 09:59:35 +1100 Subject: Reorganise: NetworkManager -> Fetcher, Models -> dedicated groups --- foray.xcodeproj/project.pbxproj | 48 ++++++++++++++++++--------- foray/Fetchers/ForayFetcher.swift | 49 +++++++++++++++++++++++++++ foray/ForayModels.swift | 20 ----------- foray/ForayNetworkManager.swift | 51 ----------------------------- foray/ForayViewModels.swift | 16 --------- foray/Models/PenguinItemModel.swift | 20 +++++++++++ foray/Models/PenguinItemViewModel.swift | 16 +++++++++ foray/Presenters/PenguinItemPresenter.swift | 18 +++++----- 8 files changed, 127 insertions(+), 111 deletions(-) create mode 100644 foray/Fetchers/ForayFetcher.swift delete mode 100644 foray/ForayModels.swift delete mode 100644 foray/ForayNetworkManager.swift delete mode 100644 foray/ForayViewModels.swift create mode 100644 foray/Models/PenguinItemModel.swift create mode 100644 foray/Models/PenguinItemViewModel.swift diff --git a/foray.xcodeproj/project.pbxproj b/foray.xcodeproj/project.pbxproj index 176b21c..0480143 100644 --- a/foray.xcodeproj/project.pbxproj +++ b/foray.xcodeproj/project.pbxproj @@ -7,8 +7,8 @@ objects = { /* Begin PBXBuildFile section */ - C011E4F127E6211400C248D6 /* ForayNetworkManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = C011E4F027E6211400C248D6 /* ForayNetworkManager.swift */; }; - C011E4F327E6216C00C248D6 /* ForayModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = C011E4F227E6216C00C248D6 /* ForayModels.swift */; }; + C011E4F127E6211400C248D6 /* ForayFetcher.swift in Sources */ = {isa = PBXBuildFile; fileRef = C011E4F027E6211400C248D6 /* ForayFetcher.swift */; }; + C011E4F327E6216C00C248D6 /* PenguinItemModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = C011E4F227E6216C00C248D6 /* PenguinItemModel.swift */; }; C049BBFE27E82B9E003820A9 /* Coordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = C049BBFD27E82B9E003820A9 /* Coordinator.swift */; }; C049BC0027E82C90003820A9 /* ForayCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = C049BBFF27E82C90003820A9 /* ForayCoordinator.swift */; }; C04B45A427DEF117001451A3 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = C04B45A327DEF117001451A3 /* AppDelegate.swift */; }; @@ -20,14 +20,14 @@ C09676BA27E86B6E00353D46 /* ForayLoadingOverlay.swift in Sources */ = {isa = PBXBuildFile; fileRef = C09676B927E86B6E00353D46 /* ForayLoadingOverlay.swift */; }; C09676BC27EC27E700353D46 /* UIViewController+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = C09676BB27EC27E700353D46 /* UIViewController+Extensions.swift */; }; C09676BE27EC28B100353D46 /* ForayDetailView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C09676BD27EC28B100353D46 /* ForayDetailView.swift */; }; - C0C73E6427EC3A650015497D /* ForayViewModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0C73E6327EC3A650015497D /* ForayViewModels.swift */; }; + C0C73E6427EC3A650015497D /* PenguinItemViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0C73E6327EC3A650015497D /* PenguinItemViewModel.swift */; }; C0C73E6727EC3BA50015497D /* PenguinItemPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0C73E6627EC3BA50015497D /* PenguinItemPresenter.swift */; }; C0FEAF5F27E14C52000A7648 /* ForayDetailViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0FEAF5E27E14C52000A7648 /* ForayDetailViewController.swift */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ - C011E4F027E6211400C248D6 /* ForayNetworkManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ForayNetworkManager.swift; sourceTree = ""; }; - C011E4F227E6216C00C248D6 /* ForayModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ForayModels.swift; sourceTree = ""; }; + C011E4F027E6211400C248D6 /* ForayFetcher.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ForayFetcher.swift; sourceTree = ""; }; + C011E4F227E6216C00C248D6 /* PenguinItemModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PenguinItemModel.swift; sourceTree = ""; }; C049BBFD27E82B9E003820A9 /* Coordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Coordinator.swift; sourceTree = ""; }; C049BBFF27E82C90003820A9 /* ForayCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ForayCoordinator.swift; sourceTree = ""; }; C04B45A027DEF117001451A3 /* foray.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = foray.app; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -40,7 +40,7 @@ C09676B927E86B6E00353D46 /* ForayLoadingOverlay.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ForayLoadingOverlay.swift; sourceTree = ""; }; C09676BB27EC27E700353D46 /* UIViewController+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIViewController+Extensions.swift"; sourceTree = ""; }; C09676BD27EC28B100353D46 /* ForayDetailView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ForayDetailView.swift; sourceTree = ""; }; - C0C73E6327EC3A650015497D /* ForayViewModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ForayViewModels.swift; sourceTree = ""; }; + C0C73E6327EC3A650015497D /* PenguinItemViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PenguinItemViewModel.swift; sourceTree = ""; }; C0C73E6627EC3BA50015497D /* PenguinItemPresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PenguinItemPresenter.swift; sourceTree = ""; }; C0FEAF5E27E14C52000A7648 /* ForayDetailViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ForayDetailViewController.swift; sourceTree = ""; }; /* End PBXFileReference section */ @@ -76,17 +76,16 @@ C04B45A227DEF117001451A3 /* foray */ = { isa = PBXGroup; children = ( - C0C73E6527EC3B8F0015497D /* Presenters */, - C09676C327EC358F00353D46 /* Coordinators */, - C09676C227EC354700353D46 /* Extensions */, - C09676C127EC353D00353D46 /* Scenes */, C04B45A327DEF117001451A3 /* AppDelegate.swift */, C04B45A527DEF117001451A3 /* SceneDelegate.swift */, - C011E4F227E6216C00C248D6 /* ForayModels.swift */, - C0C73E6327EC3A650015497D /* ForayViewModels.swift */, - C011E4F027E6211400C248D6 /* ForayNetworkManager.swift */, C04B45AC27DEF118001451A3 /* Assets.xcassets */, C04B45B127DEF118001451A3 /* Info.plist */, + C0C73E6827ED2F0A0015497D /* Models */, + C0C73E6527EC3B8F0015497D /* Presenters */, + C09676C327EC358F00353D46 /* Coordinators */, + C09676C227EC354700353D46 /* Extensions */, + C09676C127EC353D00353D46 /* Scenes */, + C0C73E6927ED2F2D0015497D /* Fetchers */, ); path = foray; sourceTree = ""; @@ -128,6 +127,23 @@ path = Presenters; sourceTree = ""; }; + C0C73E6827ED2F0A0015497D /* Models */ = { + isa = PBXGroup; + children = ( + C011E4F227E6216C00C248D6 /* PenguinItemModel.swift */, + C0C73E6327EC3A650015497D /* PenguinItemViewModel.swift */, + ); + path = Models; + sourceTree = ""; + }; + C0C73E6927ED2F2D0015497D /* Fetchers */ = { + isa = PBXGroup; + children = ( + C011E4F027E6211400C248D6 /* ForayFetcher.swift */, + ); + path = Fetchers; + sourceTree = ""; + }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ @@ -204,17 +220,17 @@ buildActionMask = 2147483647; files = ( C049BBFE27E82B9E003820A9 /* Coordinator.swift in Sources */, - C011E4F127E6211400C248D6 /* ForayNetworkManager.swift in Sources */, + C011E4F127E6211400C248D6 /* ForayFetcher.swift in Sources */, C049BC0027E82C90003820A9 /* ForayCoordinator.swift in Sources */, C09676BE27EC28B100353D46 /* ForayDetailView.swift in Sources */, C04B45B827DEF2ED001451A3 /* ForayTableViewController.swift in Sources */, C0FEAF5F27E14C52000A7648 /* ForayDetailViewController.swift in Sources */, - C0C73E6427EC3A650015497D /* ForayViewModels.swift in Sources */, + C0C73E6427EC3A650015497D /* PenguinItemViewModel.swift in Sources */, C04EDE4427E4298D00D83005 /* ForayNewTableViewCell.swift in Sources */, C09676BC27EC27E700353D46 /* UIViewController+Extensions.swift in Sources */, C04B45A427DEF117001451A3 /* AppDelegate.swift in Sources */, C09676BA27E86B6E00353D46 /* ForayLoadingOverlay.swift in Sources */, - C011E4F327E6216C00C248D6 /* ForayModels.swift in Sources */, + C011E4F327E6216C00C248D6 /* PenguinItemModel.swift in Sources */, C0C73E6727EC3BA50015497D /* PenguinItemPresenter.swift in Sources */, C04B45A627DEF117001451A3 /* SceneDelegate.swift in Sources */, ); diff --git a/foray/Fetchers/ForayFetcher.swift b/foray/Fetchers/ForayFetcher.swift new file mode 100644 index 0000000..d8df037 --- /dev/null +++ b/foray/Fetchers/ForayFetcher.swift @@ -0,0 +1,49 @@ +// +// ForayNetworkManager.swift +// foray +// +// Created by Nicholas Tay on 20/3/2022. +// + +import Foundation + +class ForayFetcher { + var basicUsername: String? = nil + var basicPassword: String? = nil + + // Reuse JSON decoder, allows for customisation of things like date decode if required + var jsonDecoder: JSONDecoder = { + let jd = JSONDecoder() + // Defaults to year-month-date format + jd.dateDecodingStrategy = .custom({ (decoder) -> Date in + let container = try decoder.singleValueContainer() + let dateStr = try container.decode(String.self) + + let dateFormat = DateFormatter() + dateFormat.dateFormat = "yyyy-MM-dd" + + return dateFormat.date(from: dateStr)! + }) + return jd + }() + + func fetch(url: String, + receiver: @escaping (T) -> ()) { + // Fetch on a background thread + DispatchQueue.global(qos: .background).async { + var request = URLRequest(url: URL(string: url)!) + request.cachePolicy = .reloadRevalidatingCacheData // Needed otherwise default caching policy seems not to check properly + + // Basic auth if required + if (self.basicUsername != nil && self.basicPassword != nil) { + let authData = (self.basicUsername! + ":" + self.basicPassword!).data(using: .utf8)!.base64EncodedString() + request.addValue("Basic \(authData)", forHTTPHeaderField: "Authorization") + } + + URLSession.shared.dataTask(with: request, completionHandler: { data, response, error -> Void in + let items = try! self.jsonDecoder.decode(T.self, from: data!) + receiver(items) + }).resume() + } + } +} diff --git a/foray/ForayModels.swift b/foray/ForayModels.swift deleted file mode 100644 index c721b95..0000000 --- a/foray/ForayModels.swift +++ /dev/null @@ -1,20 +0,0 @@ -// -// ForayItems.swift -// foray -// -// Created by Nicholas Tay on 20/3/2022. -// - -import Foundation - -enum PenguinItemType: String, Decodable { - case item - case quest -} - -struct PenguinItemModel: Decodable { - let type: PenguinItemType - let releaseDate: Date - let id: String - let name: String -} diff --git a/foray/ForayNetworkManager.swift b/foray/ForayNetworkManager.swift deleted file mode 100644 index 53e9554..0000000 --- a/foray/ForayNetworkManager.swift +++ /dev/null @@ -1,51 +0,0 @@ -// -// ForayNetworkManager.swift -// foray -// -// Created by Nicholas Tay on 20/3/2022. -// - -import Foundation - -class ForayNetworkManager { - static let shared = ForayNetworkManager() - - var basicUsername: String? = nil - var basicPassword: String? = nil - - // Reuse JSON decoder, allows for customisation of things like date decode if required - var jsonDecoder: JSONDecoder = { - let jd = JSONDecoder() - // Defaults to year-month-date format - jd.dateDecodingStrategy = .custom({ (decoder) -> Date in - let container = try decoder.singleValueContainer() - let dateStr = try container.decode(String.self) - - let dateFormat = DateFormatter() - dateFormat.dateFormat = "yyyy-MM-dd" - - return dateFormat.date(from: dateStr)! - }) - return jd - }() - - func fetch(url: String, - receiver: @escaping (T) -> ()) { - // Fetch on a background thread - DispatchQueue.global(qos: .background).async { - var request = URLRequest(url: URL(string: url)!) - request.cachePolicy = .reloadRevalidatingCacheData // Needed otherwise default caching policy seems not to check properly - - // Basic auth if required - if (self.basicUsername != nil && self.basicPassword != nil) { - let authData = (self.basicUsername! + ":" + self.basicPassword!).data(using: .utf8)!.base64EncodedString() - request.addValue("Basic \(authData)", forHTTPHeaderField: "Authorization") - } - - URLSession.shared.dataTask(with: request, completionHandler: { data, response, error -> Void in - let items = try! self.jsonDecoder.decode(T.self, from: data!) - receiver(items) - }).resume() - } - } -} diff --git a/foray/ForayViewModels.swift b/foray/ForayViewModels.swift deleted file mode 100644 index 9b9b058..0000000 --- a/foray/ForayViewModels.swift +++ /dev/null @@ -1,16 +0,0 @@ -// -// ForayViewModels.swift -// foray -// -// Created by Nicholas Tay on 24/3/2022. -// - -import Foundation - -struct PenguinItemViewModel { - let type: PenguinItemType - let releaseDateFormatted: String - let year: Int - let id: String - let name: String -} diff --git a/foray/Models/PenguinItemModel.swift b/foray/Models/PenguinItemModel.swift new file mode 100644 index 0000000..c721b95 --- /dev/null +++ b/foray/Models/PenguinItemModel.swift @@ -0,0 +1,20 @@ +// +// ForayItems.swift +// foray +// +// Created by Nicholas Tay on 20/3/2022. +// + +import Foundation + +enum PenguinItemType: String, Decodable { + case item + case quest +} + +struct PenguinItemModel: Decodable { + let type: PenguinItemType + let releaseDate: Date + let id: String + let name: String +} diff --git a/foray/Models/PenguinItemViewModel.swift b/foray/Models/PenguinItemViewModel.swift new file mode 100644 index 0000000..9b9b058 --- /dev/null +++ b/foray/Models/PenguinItemViewModel.swift @@ -0,0 +1,16 @@ +// +// ForayViewModels.swift +// foray +// +// Created by Nicholas Tay on 24/3/2022. +// + +import Foundation + +struct PenguinItemViewModel { + let type: PenguinItemType + let releaseDateFormatted: String + let year: Int + let id: String + let name: String +} diff --git a/foray/Presenters/PenguinItemPresenter.swift b/foray/Presenters/PenguinItemPresenter.swift index 2f3730f..698b56e 100644 --- a/foray/Presenters/PenguinItemPresenter.swift +++ b/foray/Presenters/PenguinItemPresenter.swift @@ -8,16 +8,18 @@ import Foundation class PenguinItemPresenter { + + let fetcher = ForayFetcher() + func fetch(receiver: @escaping ([PenguinItemViewModel]) -> ()) { - ForayNetworkManager.shared - .fetch(url: "https://users.windblume.net/~nick/upload/dummy.json") { (apiItems: [PenguinItemModel]) in - // Callback to main thread here - // There probably is a nicer way to do it, but we will DispatchQueue it back - // from the Presenter-level for now (main thread from VC onwards) - DispatchQueue.main.async { - receiver(self.transform(models: apiItems)) - } + fetcher.fetch(url: "https://users.windblume.net/~nick/upload/dummy.json") { (apiItems: [PenguinItemModel]) in + // Callback to main thread here + // There probably is a nicer way to do it, but we will DispatchQueue it back + // from the Presenter-level for now (main thread from VC onwards) + DispatchQueue.main.async { + receiver(self.transform(models: apiItems)) } + } } func transform(models: [PenguinItemModel]) -> [PenguinItemViewModel] { -- cgit