diff options
author | Nicholas Tay <nick@windblume.net> | 2022-07-17 02:13:04 +1000 |
---|---|---|
committer | Nicholas Tay <nick@windblume.net> | 2022-07-17 02:13:16 +1000 |
commit | 1adbed9f8b94521befd237c14d36325a55037a41 (patch) | |
tree | 91d81b4740514083010c72f5f0559283ccd849fa | |
parent | daee1f1b5c739f42ba54a1ebbb9655f5034e315f (diff) | |
download | forayios-1adbed9f8b94521befd237c14d36325a55037a41.tar.gz forayios-1adbed9f8b94521befd237c14d36325a55037a41.tar.bz2 forayios-1adbed9f8b94521befd237c14d36325a55037a41.zip |
Experiment with async/await
Note that URLSession async only works >=iOS 15. I changed the target for
now, but may mess with continuations.
Diffstat (limited to '')
-rw-r--r-- | foray.xcodeproj/project.pbxproj | 4 | ||||
-rw-r--r-- | foray.xcodeproj/xcshareddata/xcschemes/foray.xcscheme | 78 | ||||
-rw-r--r-- | foray/Fetchers/ForayFetcher.swift | 27 | ||||
-rw-r--r-- | foray/Presenters/PenguinItemPresenter.swift | 19 | ||||
-rw-r--r-- | foray/Scenes/ForayTableViewController.swift | 16 |
5 files changed, 111 insertions, 33 deletions
diff --git a/foray.xcodeproj/project.pbxproj b/foray.xcodeproj/project.pbxproj index 3d24015..3901dc6 100644 --- a/foray.xcodeproj/project.pbxproj +++ b/foray.xcodeproj/project.pbxproj @@ -371,7 +371,7 @@ INFOPLIST_KEY_UIMainStoryboardFile = ""; INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; - IPHONEOS_DEPLOYMENT_TARGET = 13.0; + IPHONEOS_DEPLOYMENT_TARGET = 15.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -401,7 +401,7 @@ INFOPLIST_KEY_UIMainStoryboardFile = ""; INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; - IPHONEOS_DEPLOYMENT_TARGET = 13.0; + IPHONEOS_DEPLOYMENT_TARGET = 15.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", diff --git a/foray.xcodeproj/xcshareddata/xcschemes/foray.xcscheme b/foray.xcodeproj/xcshareddata/xcschemes/foray.xcscheme new file mode 100644 index 0000000..09e83ac --- /dev/null +++ b/foray.xcodeproj/xcshareddata/xcschemes/foray.xcscheme @@ -0,0 +1,78 @@ +<?xml version="1.0" encoding="UTF-8"?> +<Scheme + LastUpgradeVersion = "1340" + version = "1.3"> + <BuildAction + parallelizeBuildables = "YES" + buildImplicitDependencies = "YES"> + <BuildActionEntries> + <BuildActionEntry + buildForTesting = "YES" + buildForRunning = "YES" + buildForProfiling = "YES" + buildForArchiving = "YES" + buildForAnalyzing = "YES"> + <BuildableReference + BuildableIdentifier = "primary" + BlueprintIdentifier = "C04B459F27DEF117001451A3" + BuildableName = "foray.app" + BlueprintName = "foray" + ReferencedContainer = "container:foray.xcodeproj"> + </BuildableReference> + </BuildActionEntry> + </BuildActionEntries> + </BuildAction> + <TestAction + buildConfiguration = "Debug" + selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" + selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" + shouldUseLaunchSchemeArgsEnv = "YES"> + <Testables> + </Testables> + </TestAction> + <LaunchAction + buildConfiguration = "Debug" + selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" + selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" + launchStyle = "0" + useCustomWorkingDirectory = "NO" + ignoresPersistentStateOnLaunch = "NO" + debugDocumentVersioning = "YES" + debugServiceExtension = "internal" + allowLocationSimulation = "YES"> + <BuildableProductRunnable + runnableDebuggingMode = "0"> + <BuildableReference + BuildableIdentifier = "primary" + BlueprintIdentifier = "C04B459F27DEF117001451A3" + BuildableName = "foray.app" + BlueprintName = "foray" + ReferencedContainer = "container:foray.xcodeproj"> + </BuildableReference> + </BuildableProductRunnable> + </LaunchAction> + <ProfileAction + buildConfiguration = "Release" + shouldUseLaunchSchemeArgsEnv = "YES" + savedToolIdentifier = "" + useCustomWorkingDirectory = "NO" + debugDocumentVersioning = "YES"> + <BuildableProductRunnable + runnableDebuggingMode = "0"> + <BuildableReference + BuildableIdentifier = "primary" + BlueprintIdentifier = "C04B459F27DEF117001451A3" + BuildableName = "foray.app" + BlueprintName = "foray" + ReferencedContainer = "container:foray.xcodeproj"> + </BuildableReference> + </BuildableProductRunnable> + </ProfileAction> + <AnalyzeAction + buildConfiguration = "Debug"> + </AnalyzeAction> + <ArchiveAction + buildConfiguration = "Release" + revealArchiveInOrganizer = "YES"> + </ArchiveAction> +</Scheme> diff --git a/foray/Fetchers/ForayFetcher.swift b/foray/Fetchers/ForayFetcher.swift index d8df037..e4c6fd9 100644 --- a/foray/Fetchers/ForayFetcher.swift +++ b/foray/Fetchers/ForayFetcher.swift @@ -27,23 +27,18 @@ class ForayFetcher { return jd }() - func fetch<T: Decodable>(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") - } + func fetch<T: Decodable>(url: String) async throws -> T { + var request = URLRequest(url: URL(string: url)!) + request.cachePolicy = .reloadRevalidatingCacheData // Needed otherwise default caching policy seems not to check properly - URLSession.shared.dataTask(with: request, completionHandler: { data, response, error -> Void in - let items = try! self.jsonDecoder.decode(T.self, from: data!) - receiver(items) - }).resume() + // 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") } + + let (data, _) = try await URLSession.shared.data(for: request) + let items = try jsonDecoder.decode(T.self, from: data) + return items } } diff --git a/foray/Presenters/PenguinItemPresenter.swift b/foray/Presenters/PenguinItemPresenter.swift index c4553ae..1d617bf 100644 --- a/foray/Presenters/PenguinItemPresenter.swift +++ b/foray/Presenters/PenguinItemPresenter.swift @@ -8,18 +8,19 @@ import Foundation class PenguinItemPresenter { + + private struct Constants { + static let apiEndpoint = "https://users.windblume.net/~nick/upload/dummy.json" + } let fetcher = ForayFetcher() - func fetch(receiver: @escaping ([PenguinItemViewModel]) -> ()) { - fetcher.fetch(url: "https://users.windblume.net/~nick/upload/dummy.json") { [weak self] (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 { - guard let self = self else { return } - receiver(self.transform(models: apiItems)) - } + func fetch() async -> [PenguinItemViewModel] { + do { + let apiItems: [PenguinItemModel] = try await fetcher.fetch(url: Constants.apiEndpoint) + return transform(models: apiItems) + } catch { + return [] } } diff --git a/foray/Scenes/ForayTableViewController.swift b/foray/Scenes/ForayTableViewController.swift index a29088c..849553c 100644 --- a/foray/Scenes/ForayTableViewController.swift +++ b/foray/Scenes/ForayTableViewController.swift @@ -42,21 +42,25 @@ class ForayTableViewController: UITableViewController, Coordinated { self.refreshControl?.addTarget(self, action: #selector(doRefresh), for: UIControl.Event.valueChanged) } - @objc func doRefresh(sender: AnyObject) { + @objc + func doRefresh(sender: AnyObject) { reloadApiData() } func reloadApiData() { - presenter.fetch { [weak self] (data: [PenguinItemViewModel]) in - guard let self = self else { return } - - let groups = Dictionary(grouping: data) { $0.year } + Task(priority: .medium) { [weak self] in + let models = await self?.presenter.fetch() + + guard let self = self, + let models = models else { return } + + let groups = Dictionary(grouping: models) { $0.year } self.sections = groups.map { (key, values) in return YearSection(year: key, items: values) } // Sort the sections from oldest year to newest self.sections.sort { (lhs, rhs) in lhs.year < rhs.year } - + self.tableView.reloadData() self.refreshControl?.endRefreshing() self.coordinator?.hideLoading() |