aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNicholas Tay <nick@windblume.net>2022-07-17 02:13:04 +1000
committerNicholas Tay <nick@windblume.net>2022-07-17 02:13:16 +1000
commit1adbed9f8b94521befd237c14d36325a55037a41 (patch)
tree91d81b4740514083010c72f5f0559283ccd849fa
parentdaee1f1b5c739f42ba54a1ebbb9655f5034e315f (diff)
downloadforayios-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.
-rw-r--r--foray.xcodeproj/project.pbxproj4
-rw-r--r--foray.xcodeproj/xcshareddata/xcschemes/foray.xcscheme78
-rw-r--r--foray/Fetchers/ForayFetcher.swift27
-rw-r--r--foray/Presenters/PenguinItemPresenter.swift19
-rw-r--r--foray/Scenes/ForayTableViewController.swift16
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()