diff --git a/EmployeeDirectory/Services/EmployeeCacheService.swift b/EmployeeDirectory/Services/EmployeeCacheService.swift new file mode 100644 index 0000000..8f68ebb --- /dev/null +++ b/EmployeeDirectory/Services/EmployeeCacheService.swift @@ -0,0 +1,44 @@ +// +// EmployeeCacheService.swift +// EmployeeDirectory +// +// Created by Matt Bruce on 2/6/25. +// + +import Foundation +import UIKit + +/// A service that handles image caching using memory, disk, and network in priority order. +public class EmployeeCacheService { + // MARK: - Properties + public static let shared = EmployeeCacheService() // Default shared instance + + /// Memory cache for storing images in RAM. + private let emplyoees: Employees? = nil + + /// File manager for handling disk operations. + private let fileManager = FileManager.default + + /// Directory where cached images are stored on disk. + private let cacheDirectory: URL = { + FileManager.default.urls(for: .cachesDirectory, in: .userDomainMask)[0] + }() + + // MARK: - Initializer + + public init() {} + + public func save(from employees: Employees) throws { + let data = try JSONEncoder().encode(employees) + try data.write(to: cacheDirectory.appendingPathComponent("employees.json")) + } + + public func load() throws -> Employees { + let data = try Data(contentsOf: cacheDirectory.appendingPathComponent("employees.json")) + return try JSONDecoder().decode(Employees.self, from: data) + } + + public func clear() { + try? FileManager.default.removeItem(at: cacheDirectory.appendingPathComponent("employees.json")) + } +} diff --git a/EmployeeDirectory/Services/EmployeeService.swift b/EmployeeDirectory/Services/EmployeeService.swift index 27b9780..037b12c 100644 --- a/EmployeeDirectory/Services/EmployeeService.swift +++ b/EmployeeDirectory/Services/EmployeeService.swift @@ -36,8 +36,14 @@ internal enum EmployeeServiceMode: String, CaseIterable { } } + /// Service Layer for Employees public class EmployeeService: EmployeeServiceProtocol { + public enum EmployeeServiceError: Error { + case error + //case LoadError + //case other(Error) + } // MARK: - Properties public static let shared = EmployeeService() // Default shared instance @@ -51,7 +57,29 @@ public class EmployeeService: EmployeeServiceProtocol { /// - Parameter serviceMode: Mode in which to hit. /// - Returns: An Employees struct public func getEmployees() async throws -> Employees { - return try await NetworkService.shared.fetchData(from: EmployeeServiceMode.production.endpoint, as: Employees.self) + var employees: Employees + let cache = EmployeeCacheService.shared + do { + employees = try cache.load() + return employees + } catch { + if let networkFound = try? await fetchNetworkEmployees() { + employees = networkFound + return employees + } + } + throw EmployeeServiceError.error + } + + public func fetchNetworkEmployees() async throws -> Employees { + var employees: Employees + if let networkFound = try? await NetworkService.shared.fetchData(from: EmployeeServiceMode.production.endpoint, as: Employees.self) { + employees = networkFound + try? EmployeeCacheService.shared.save(from: employees) + return employees + } else { + throw EmployeeServiceError.error + } } }