我使用Realm Swift 0.95.3。在我的项目中,我使用的是联系人(不是联系人AddressBook),其中包含有关姓名,姓氏,中间名,电子邮件,...和照片的信息。
我创建了一个名为Contact
的Object子类。我知道图像或任何其他二进制数据不应存储在Realm中。特别是因为我的图像足够大~5 Mb。
无论如何,我想将图像存储在文件系统中,而Realm只存储指向该图像的链接。我认为将来我可能需要将其他文件(音频,PDF,...)附加到Object的子类。所以我决定创建一个单独的类File,它继承自Object。整个结构看起来像。
class File: Object {
dynamic var objectID = NSUUID().UUIDString
private var filePath: String {
let paths = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)
let documentsDirectory = paths[0] as NSString
return documentsDirectory.stringByAppendingPathComponent(objectID)
}
lazy var fileData: NSData? = {
return self.readFile()
}()
override static func primaryKey() -> String? {
return "objectID"
}
override static func ignoredProperties() -> [String] {
return ["fileData"]
}
override func copy() -> AnyObject {
let result = File(value: self)
result.objectID = NSUUID().UUIDString
result.fileData = fileData?.copy() as? NSData
return result
}
}
extension File {
//MARK:-
private func readFile() -> NSData? {
let lFilePath = filePath
print("Try to read file \(lFilePath)")
return NSData(contentsOfFile: lFilePath)
}
private func writeFileWithFileData() {
if let lFileData = fileData {
lFileData.writeToFile(filePath, atomically: true)
print("File \(filePath) was created")
} else {
removeFile()
}
}
private func removeFile() {
do {
try NSFileManager.defaultManager().removeItemAtPath(filePath)
print("File \(filePath) was removed")
} catch {
print(error)
}
}
}
如您所见,在尝试获取属性fileData
时,会从文件系统接收数据。此外,fileData
使用关键字lazy
声明,也就是说,我希望从磁盘请求数据缓存在此属性中。如果在保存到数据库之前更改了此属性,File对象,则调用writeFileWithFileData(),并覆盖磁盘上的数据。这个系统按照我的需要工作,我要进行实验。然后我创建了一个联系人。
class Contact: Object {
dynamic var objectID = NSUUID().UUIDString
dynamic var firstName = ""
dynamic var lastName = ""
...
private dynamic var avatarFile: File?
var avatar: UIImage? {
get {
guard let imageData = avatarFile?.fileData else { return nil }
return UIImage(data: imageData)
}
set {
avatarFile = File()
guard let imageData = newValue else {
avatarFile?.fileData = nil
return
}
avatarFile?.fileData = UIImagePNGRepresentation(imageData)
}
}
override static func primaryKey() -> String? {
return "objectID"
}
override static func ignoredProperties() -> [String] {
return ["image"]
}
}
问题在于,当我从数据库中选择联系人并尝试获取头像时,每次访问此属性时都会访问文件系统。也就是说,属性fileData不像懒惰那样运行 - 就像我刚开始想的那样。但后来我查看了内存地址属性avatarFile,每次收到它时,地址都发生了变化。由此可以得出结论,对象avatarFile不断从数据库中再次请求,并且对该属性有任何引用。因此,所有被忽略的属性都会被重置。
答案 0 :(得分:0)
应该没问题。领域对象是其父Realm对象的实时链接,而不是静态副本,因此它们的地址会定期更改。这是正常的,并且没有重新分配对象,因此您不应该在此处看到任何内存问题。据我所知,NSData
本身是懒惰的,因此在您明确请求之前,实际上不会读取数据。
您的建筑看起来很棒!你是对的,它通常不是直接在Realm文件中存储文件数据的最佳形式,但你已经做好了使Realm Object管理外部文件数据的好工作。 :)