Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Core/Entities/AddPersonParameters.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

import Foundation

public struct AddPersonParameters: Equatable {
public struct AddPersonParameters: Equatable, Sendable {
public var name: String
public var dayOfBirth: Date
public var timeOfBirth: Date
Expand Down
2 changes: 1 addition & 1 deletion Core/Entities/Person.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

import Foundation

public struct Person: Equatable, Hashable {
public struct Person: Equatable, Hashable, Sendable {

public var id: UUID
public var name: String
Expand Down
54 changes: 0 additions & 54 deletions Core/EntityGateway/Cache/CachePersonsGateway.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,18 +18,6 @@ public final class CachePersonsGateway: PersonsGateway {
self.imageStore = imageStore
}

public func add(parameters: AddPersonParameters, completionHandler: @escaping AddPersonEntityGatewayCompletionHandler) {
Task {
do {
await complete(.success(try await add(parameters: parameters)), using: completionHandler)
} catch let error as CoreError {
await complete(.failure(error), using: completionHandler)
} catch {
await complete(.failure(CoreError(error: error)), using: completionHandler)
}
}
}

public func add(parameters: AddPersonParameters) async throws -> Person {
try Task.checkCancellation()
let savedImages = try await save(newImages(in: parameters))
Expand All @@ -42,37 +30,14 @@ public final class CachePersonsGateway: PersonsGateway {
}
}

public func fetchPersons(completionHandler: @escaping FetchPersonsEntityGatewayCompletionHandler) {
coreDataGateway.fetchPersons(completionHandler: completionHandler)
}

public func fetchPersons() async throws -> [Person] {
try await coreDataGateway.fetchPersons()
}

public func fetchWidgetPersons(completion: @escaping FetchPersonsEntityGatewayCompletionHandler) {
coreDataGateway.fetchWidgetPersons(completion: completion)
}

public func fetchWidgetPersons() async throws -> [Person] {
try await coreDataGateway.fetchWidgetPersons()
}

public func edit(
person: Person, with parameters: AddPersonParameters,
completionHandler: @escaping EditPersonEntityGatewayCompletionHandler
) {
Task {
do {
await complete(.success(try await edit(person: person, with: parameters)), using: completionHandler)
} catch let error as CoreError {
await complete(.failure(error), using: completionHandler)
} catch {
await complete(.failure(CoreError(error: error)), using: completionHandler)
}
}
}

public func edit(person: Person, with parameters: AddPersonParameters) async throws -> Person {
try Task.checkCancellation()
let savedImages = try await save(newImages(in: parameters))
Expand All @@ -87,19 +52,6 @@ public final class CachePersonsGateway: PersonsGateway {
}
}

public func remove(person: Person, completionHandler: @escaping RemovePersonEntityGatewayCompletionHandler) {
Task {
do {
try await remove(person: person)
await complete(.success(()), using: completionHandler)
} catch let error as CoreError {
await complete(.failure(error), using: completionHandler)
} catch {
await complete(.failure(CoreError(error: error)), using: completionHandler)
}
}
}

public func remove(person: Person) async throws {
try Task.checkCancellation()
try await coreDataGateway.remove(person: person)
Expand Down Expand Up @@ -154,10 +106,4 @@ public final class CachePersonsGateway: PersonsGateway {
}
}
}

private func complete<Value>(
_ result: Result<Value, CoreError>, using completion: @escaping (Result<Value, CoreError>) -> Void
) async {
await MainActor.run { completion(result) }
}
}
34 changes: 16 additions & 18 deletions Core/EntityGateway/Cache/ImagesCache.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,26 +14,24 @@ public enum ImagesCache {

public static let memoryCache = MemoryCache<UIImage>()

public static func loadImageFromDiskOrMemory(
image: PersonImage, completion: @escaping (Result<UIImage, CoreError>) -> Void
) {
DispatchQueue.global(qos: .userInitiated).async {
var result = Result<UIImage, CoreError>.failure(.unknownError)
if let memoryImg = memoryCache.value(forKey: image.cachingKey) {
result = .success(memoryImg)
} else {
let directory = Disk.Directory.sharedContainer(appGroupName: Constants.appGroupId)
do {
let image = try Disk.retrieve(image.cachingKey, from: directory, as: UIImage.self)
result = .success(image)
} catch {
let coreError = CoreError(error: error)
result = .failure(coreError)
public static func loadImageFromDiskOrMemory(image: PersonImage) async throws -> UIImage {
try Task.checkCancellation()
let loadedImage = try await withCheckedThrowingContinuation { continuation in
DispatchQueue.global(qos: .userInitiated).async {
if let memoryImg = memoryCache.value(forKey: image.cachingKey) {
continuation.resume(returning: memoryImg)
} else {
let directory = Disk.Directory.sharedContainer(appGroupName: Constants.appGroupId)
do {
continuation.resume(
returning: try Disk.retrieve(image.cachingKey, from: directory, as: UIImage.self))
} catch {
continuation.resume(throwing: CoreError(error: error))
}
}
}
DispatchQueue.main.async {
completion(result)
}
}
try Task.checkCancellation()
return loadedImage
}
}
186 changes: 84 additions & 102 deletions Core/EntityGateway/LocalPersistance/CoreDataPersonsGateway.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,6 @@
import CoreData
import Foundation

public typealias FetchedPersonsCompletionHandler = (_ persons: Result<[Person], CoreError>) -> Void
public typealias FetchedPersonCompletionHandler = (_ person: Result<Person, CoreError>) -> Void

public class CoreDataPersonsGateway: PersonsGateway {

let coreDataStack: CoreDataStack
Expand All @@ -20,129 +17,114 @@ public class CoreDataPersonsGateway: PersonsGateway {
self.coreDataStack = coreDataStack
}

public func add(parameters: AddPersonParameters, completionHandler: @escaping AddPersonEntityGatewayCompletionHandler) {
coreDataStack.persistentContainer.performBackgroundTask { context in
var result: Result<Person, CoreError> = .failure(CoreError.coreDataAddFailed)
if let cdPerson = context.addEntity(withType: CoreDataPerson.self) {
cdPerson.populate(with: parameters)
public func add(parameters: AddPersonParameters) async throws -> Person {
try Task.checkCancellation()
return try await withCheckedThrowingContinuation { continuation in
coreDataStack.persistentContainer.performBackgroundTask { context in
guard let person = context.addEntity(withType: CoreDataPerson.self) else {
continuation.resume(throwing: CoreError.coreDataAddFailed)
return
}
do {
if parameters.isOnWidget {
cdPerson.accessToWidget = try AccessToWidget.sharedInstance(in: context)
} else {
cdPerson.accessToWidget = nil
}
person.populate(with: parameters)
person.accessToWidget =
parameters.isOnWidget
? try AccessToWidget.sharedInstance(in: context) : nil
try context.save()
result = .success(cdPerson.person)
continuation.resume(returning: person.person)
} catch let error as CoreError {
context.delete(cdPerson)
result = .failure(error)
context.delete(person)
continuation.resume(throwing: error)
} catch {
context.delete(cdPerson)
result = .failure(CoreError(error: error))
context.delete(person)
continuation.resume(throwing: CoreError(error: error))
}
}
DispatchQueue.main.async {
completionHandler(result)
}
}
}

public func fetchPersons(completionHandler: @escaping FetchPersonsEntityGatewayCompletionHandler) {
coreDataStack.persistentContainer.performBackgroundTask { _ in
var result: Result<[Person], CoreError> = .failure(.unknownError)
let fetchRequest: NSFetchRequest<CoreDataPerson> = CoreDataPerson.fetchRequest()
fetchRequest.sortDescriptors = [NSSortDescriptor(key: "createdDate", ascending: true)]
do {
let persons = try fetchRequest.execute().map({ $0.person })
result = .success(persons)
} catch {
let coreError = CoreError(error: error)
result = .failure(coreError)
}
DispatchQueue.main.async {
completionHandler(result)
public func fetchPersons() async throws -> [Person] {
try Task.checkCancellation()
let persons = try await withCheckedThrowingContinuation { continuation in
coreDataStack.persistentContainer.performBackgroundTask { context in
let request: NSFetchRequest<CoreDataPerson> = CoreDataPerson.fetchRequest()
request.sortDescriptors = [NSSortDescriptor(key: "createdDate", ascending: true)]
do {
continuation.resume(returning: try context.fetch(request).map(\.person))
} catch {
continuation.resume(throwing: CoreError(error: error))
}
}
}
try Task.checkCancellation()
return persons
}

public func fetchWidgetPersons(completion: @escaping FetchPersonsEntityGatewayCompletionHandler) {
coreDataStack.persistentContainer.performBackgroundTask { context in
var result: Result<[Person], CoreError> = .failure(.unknownError)
do {
let access = try AccessToWidget.sharedInstance(in: context)
guard let persons = access.widgetPersons else {
throw CoreError.missingValue
public func fetchWidgetPersons() async throws -> [Person] {
try Task.checkCancellation()
let persons = try await withCheckedThrowingContinuation { continuation in
coreDataStack.persistentContainer.performBackgroundTask { context in
do {
guard let persons = try AccessToWidget.sharedInstance(in: context).widgetPersons else {
throw CoreError.missingValue
}
continuation.resume(returning: persons.map(\.person).sorted())
} catch let error as CoreError {
continuation.resume(throwing: error)
} catch {
continuation.resume(throwing: CoreError(error: error))
}
let cdPersons = Array(persons.map({ $0.person })).sorted()
result = .success(cdPersons)
} catch let error as CoreError {
result = .failure(error)
} catch {
let coreError = CoreError(error: error)
result = .failure(coreError)
}
DispatchQueue.main.async {
completion(result)
}
}
try Task.checkCancellation()
return persons
}

public func edit(
person: Person, with parameters: AddPersonParameters,
completionHandler: @escaping EditPersonEntityGatewayCompletionHandler
) {
coreDataStack.persistentContainer.performBackgroundTask { context in
var result: Result<Person, CoreError> = .failure(CoreError.unknownError)
do {
let predicate = NSPredicate(format: "%K == %@", #keyPath(CoreDataPerson.id), person.id.uuidString)
let fetchRequest: NSFetchRequest<CoreDataPerson> = CoreDataPerson.fetchRequest()
fetchRequest.predicate = predicate
let coreDataPerson = try fetchRequest.execute().first
guard let cdPerson = coreDataPerson else {
throw CoreError.coreDataFetchFailed
}
cdPerson.populate(with: parameters)
if parameters.isOnWidget {
cdPerson.accessToWidget = try AccessToWidget.sharedInstance(in: context)
} else {
cdPerson.accessToWidget = nil
public func edit(person: Person, with parameters: AddPersonParameters) async throws -> Person {
try Task.checkCancellation()
return try await withCheckedThrowingContinuation { continuation in
coreDataStack.persistentContainer.performBackgroundTask { context in
do {
let request: NSFetchRequest<CoreDataPerson> = CoreDataPerson.fetchRequest()
request.predicate = NSPredicate(
format: "%K == %@", #keyPath(CoreDataPerson.id), person.id.uuidString)
guard let storedPerson = try context.fetch(request).first else {
throw CoreError.coreDataFetchFailed
}
storedPerson.populate(with: parameters)
storedPerson.accessToWidget =
parameters.isOnWidget
? try AccessToWidget.sharedInstance(in: context) : nil
try context.save()
continuation.resume(returning: storedPerson.person)
} catch let error as CoreError {
continuation.resume(throwing: error)
} catch {
continuation.resume(throwing: CoreError(error: error))
}
try context.save()
result = .success(cdPerson.person)
} catch let coreError as CoreError {
result = .failure(coreError)
} catch {
let coreError = CoreError(error: error)
result = .failure(coreError)
}
DispatchQueue.main.async {
completionHandler(result)
}
}
}

public func remove(person: Person, completionHandler: @escaping RemovePersonEntityGatewayCompletionHandler) {
coreDataStack.persistentContainer.performBackgroundTask { context in
var result: Result<Void, CoreError> = .failure(.unknownError)
do {
let predicate = NSPredicate(format: "%K == %@", #keyPath(CoreDataPerson.id), person.id.uuidString)
let fetchRequest: NSFetchRequest<CoreDataPerson> = CoreDataPerson.fetchRequest()
fetchRequest.predicate = predicate
let coreDataPerson = try fetchRequest.execute().first
guard let cdPerson = coreDataPerson else {
throw CoreError.coreDataFetchFailed
public func remove(person: Person) async throws {
try Task.checkCancellation()
try await withCheckedThrowingContinuation { continuation in
coreDataStack.persistentContainer.performBackgroundTask { context in
do {
let request: NSFetchRequest<CoreDataPerson> = CoreDataPerson.fetchRequest()
request.predicate = NSPredicate(
format: "%K == %@", #keyPath(CoreDataPerson.id), person.id.uuidString)
guard let storedPerson = try context.fetch(request).first else {
throw CoreError.coreDataFetchFailed
}
context.delete(storedPerson)
try context.save()
continuation.resume(returning: ())
} catch let error as CoreError {
continuation.resume(throwing: error)
} catch {
continuation.resume(throwing: CoreError(error: error))
}
context.delete(cdPerson)
try context.save()
result = .success(())
} catch let error as CoreError {
result = .failure(error)
} catch {
let coreError = CoreError(error: error)
result = .failure(coreError)
}
DispatchQueue.main.async {
completionHandler(result)
}
}
}
Expand Down
Loading
Loading