Я пытаюсь создать стандартную c постоянную подпрограмму для личного пакета Swift, который я могу использовать в своих собственных проектах.
Идея:
- Я могу накормить
save(instance:)
метод, и он - создаст новую папку в папке документов с именем типа экземпляра, который я передаю (т. Е. Если я передаю экземпляр
Contact
, папка будет называться Contact
- сохранить экземпляр как json
- , чтобы загрузить все экземпляры определенного типа c, я хочу использовать метод
loadAll(of type:)
, который - декодирует все файлы в этой папке, если она существует
- возвращает массив этих экземпляров
Вот класс сохраняемости пакетов:
public class ATPersistLocally {
public static let shared = ATPersistLocally()
private let encoder = JSONEncoder()
private let decoder = JSONDecoder()
private let fileManager: FileManager = {
return FileManager.default
}()
private let docPath: URL = {
let urls = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
guard let docPath = urls.first else { fatalError() }
ATLogger.shared.logToConsole(message: "Doc path is: \(docPath)", type: .debug)
return docPath
}()
//MARK: - Loading
public func loadAll<T: Codable & Identifiable>(of type: T) -> [T] {
var result = [T]()
let typeName = getTypeName(of: type) //custom helper method, see below
let pathFolder = docPath.appendingPathComponent(String(describing: typeName))
if fileManager.fileExists(atPath: pathFolder.path) {
var urls = [URL]()
do {
urls = try fileManager.contentsOfDirectory(at: pathFolder, includingPropertiesForKeys: nil, options: .skipsHiddenFiles)
} catch let error {
ATLogger.shared.logToConsole(message: "Could not load content of directory: \(error.localizedDescription)", type: .error)
}
for url in urls {
if let data = fileManager.contents(atPath: url.path) {
do {
let instance = try decoder.decode(T.self, from: data)
result.append(instance)
} catch let error {
ATLogger.shared.logToConsole(message: "Could not decode data: \(error.localizedDescription)", type: .error)
}
}
}
}
return result
}
//MARK: - Saving
public func save<T: Codable & Identifiable>(instance: T) {
let typeName = getTypeName(of: instance)
let pathFolder = docPath.appendingPathComponent(String(describing: typeName))
if !fileManager.fileExists(atPath: pathFolder.absoluteString) {
do {
try fileManager.createDirectory(atPath: pathFolder.relativePath, withIntermediateDirectories: true)
} catch let error {
ATLogger.shared.logToConsole(message: "Could not create folder for type \(typeName): \(error.localizedDescription)", type: .error)
}
}
let path = pathFolder.appendingPathComponent(instance.id as! String)
do {
let data = try encoder.encode(instance)
do {
try data.write(to: URL(fileURLWithPath: path.relativePath))
ATLogger.shared.logToConsole(message: "Saved instance of \(typeName)", type: .debug)
} catch let error {
ATLogger.shared.logToConsole(message: "Could not save data: \(error.localizedDescription)", type: .error)
}
} catch let error {
ATLogger.shared.logToConsole(message: "Could not encode data: \(error.localizedDescription)", type: .error)
}
}
//MARK: - Helper Functions
private func getTypeName<T: Codable & Identifiable>(of type: T) -> T.Type {
return T.self
}
}
Хотя эта компиляция и сохранение уже работает нормально, у меня есть проблема с загрузкой.
Вот пример структуры (которая должна быть Codable & Identifiable
, если я правильно понимаю), что я пытаюсь использовать:
import Foundation
struct Contact: Codable, Identifiable {
let id = UUID()
let contactTitle: String
var name: String? = nil
var firstname: String? = nil
var address: String? = nil
var zip: String? = nil
var city: String? = nil
}
А вот вызов загрузки, который я пытаюсь сделать e:
var contacts = ATPersistLocally.shared.loadAll(of: Contact.self)
Ошибка, которую я получаю во время сборки: Argument type 'Contact.Type' does not conform to expected type 'Decodable'
.
Я также попытался вызвать contacts = ATPersistLocally.shared.loadAll(of: Contact)
, что приводит к точно так же сообщению об ошибке.
Очевидно, что я неправильно понимаю кое-что, касающееся концепции генериков здесь - поэтому любой намек в правильном направлении будет высоко оценен!