我想知道将 3D 模型存储在 Core Data 中是否高效且有意义?如果不是,最佳解决方案是什么?像 Firebase 之类的东西还是?
我目前正在使用 CoreData,但如果用户导入更大的模型,我担心存储和性能。
我认为核心数据不会对整个流程产生任何明显的性能影响。该过程是导入/下载大文件或数据块,然后存储并稍后在应用程序中读取、解析和使用。
在核心数据模型中,您可以有一个二进制数据类型的字段,并带有允许外部存储选项。这旨在将您的数据(需要时)存储为外部文件。在您实际访问项目的属性之前,不会加载该文件。即使在访问它之后,它也应该返回数据作为映射文件,以便内存消耗最小。
但另一方面,我一开始就看不出使用数据库有什么好处。只有当您可以预期大量项目、引入关系等时,数据库才会派上用场。如果您需要使用获取的结果控制器或使用查询来基于搜索文本等过滤器获取项目,它将派上用场。而这些都不能在二进制数据上实现。
如果您的项目确实包含一些元数据,例如您的模型有标签、作者和评论等,那么最好将这些数据放入数据库并从数据库可以提供的所有内容中受益。之后,您仍然可以选择将二进制数据保留在数据库中,也可以使用普通文件来保存二进制数据,同时将文件名保存在数据库中。
一般来说,处理文件需要付出一点努力,但不会太多。可能比实现任何数据库要少得多。快速实施可能如下所示
class ModelsFileManager {
struct ModelMetadata: Codable {
fileprivate let localID: UUID
let name: String
let author: String
let tags: [String]
}
let modelPathExtension: String = "3DModel"
let metadataPathExtension: String = "3DModelMetadata"
let folderName: String
private let directoryPath: URL
init(folderName: String = "3D models") {
self.folderName = folderName
directoryPath = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0].appending(component: folderName)
}
private func modelPathWithID(_ id: UUID) -> URL {
directoryPath.appendingPathComponent(id.uuidString).appendingPathExtension(modelPathExtension)
}
private func metadataPathWithID(_ id: UUID) -> URL {
directoryPath.appendingPathComponent(id.uuidString).appendingPathExtension(metadataPathExtension)
}
func insertNewModel(file: URL, modelInfo: (name: String, author: String, tags: [String])) throws {
let metadata = ModelMetadata(localID: .init(),
name: modelInfo.name,
author: modelInfo.author,
tags: modelInfo.tags)
if !FileManager.default.fileExists(atPath: directoryPath.path) {
try FileManager.default.createDirectory(at: directoryPath, withIntermediateDirectories: true)
}
try FileManager.default.moveItem(at: file, to: modelPathWithID(metadata.localID))
let metadataFile = try JSONEncoder().encode(metadata)
try metadataFile.write(to: metadataPathWithID(metadata.localID))
}
func loadAllMetadata() throws -> [ModelMetadata] {
try FileManager.default.contentsOfDirectory(at: directoryPath, includingPropertiesForKeys: nil)
.filter { $0.pathExtension == metadataPathExtension }
.compactMap {
let data = try Data(contentsOf: $0)
return try? JSONDecoder().decode(ModelMetadata.self, from: data)
}
}
func modelPathForMetadata(_ metadata: ModelMetadata) -> URL {
modelPathWithID(metadata.localID)
}
}
这个想法是将模型下载到临时目录,然后使用
insetNewModel
移动它并附加所有信息。之后 loadAllMetadata
应该为您提供访问和管理模型和附加信息的所有权力。您可以获得模型的 URL,然后根据需要将其转换为 Data
。