为什么我的关系对象每次访问时都会重新初始化?

时间:2015-11-07 18:43:25

标签: ios database swift realm relation

我使用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不断从数据库中再次请求,并且对该属性有任何引用。因此,所有被忽略的属性都会被重置。

  1. 为什么每次访问关系对象时都会重新初始化它?
  2. 分享您对我的拱门的看法

1 个答案:

答案 0 :(得分:0)

  1. 应该没问题。领域对象是其父Realm对象的实时链接,而不是静态副本,因此它们的地址会定期更改。这是正常的,并且没有重新分配对象,因此您不应该在此处看到任何内存问题。据我所知,NSData本身是懒惰的,因此在您明确请求之前,实际上不会读取数据。

  2. 您的建筑看起来很棒!你是对的,它通常不是直接在Realm文件中存储文件数据的最佳形式,但你已经做好了使Realm Object管理外部文件数据的好工作。 :)