swift领域插入数组在后台线程中使用main

时间:2017-09-10 13:51:25

标签: ios swift asynchronous realm grand-central-dispatch

我有一个通过rest响应接收的对象数组,我想在后台线程中插入到realm db中,并在 main 线程中的uicollectionview中使用。 一旦我收到rest的响应,我就会调用回调函数并在后台线程中将数组插入db。 当我试图访问在后台插入的对象的主线程属性时我遇到的问题我因为尚未插入的对象而得到异常(见下面

  

由于未捕获的异常终止应用' RLMException',原因:   ' Realm从错误的线程访问。

模型

class User : Object, Mappable {
    dynamic var firstName: String?
    dynamic var lastName: String?

    required convenience init?(map: Map){
        self.init()
    }

    func mapping(map: Map) {
        firstName <- map["firstName"]
        lastName <- map["lastName"]
    }
}

插入后台线程......

DispatchQueue.global().async {
  let realm = try! Realm()
  try! realm.write {
    realm.add(users)
  }
}

在UI中渲染...

    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
    let cell = self.collectionView.dequeueReusableCell(withReuseIdentifier: "MyCell", for: indexPath) as! UserViewCell

    let user = users[indexPath.row]
    cell.firstName.text = user.firstName
    cell.lastName.text = user.lastName
}

请注意,访问firstName或lastName时会发生异常。

请让我知道我在这里做错了什么

1 个答案:

答案 0 :(得分:1)

最简单的解决方案是在主线程上创建对Realm实例的新引用,并使用新创建的引用从域中获取所有用户,这样您就可以从同一个线程访问域。

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
    let cell = self.collectionView.dequeueReusableCell(withReuseIdentifier: "MyCell", for: indexPath) as! UserViewCell

    let users = try! Realm().objects(User.self)
    let user = users[indexPath.row]
    cell.firstName.text = user.firstName
    cell.lastName.text = user.lastName
}

另一种解决方案是使用ThreadSafeReference对象将users数组从后台线程传递到主线程。但是,如果ThreadSafeReference的类型为users users,则您只能为Results的集合创建一个List。如果users类型为Results<User>,请参阅下面的代码。

var usersRef: ThreadSafeReference<Results<User>>?
DispatchQueue.global().async {
    autoreleasepool{
        let realm = try! Realm()
        try! realm.write {
            realm.add(users)
        }
        usersRef = ThreadSafeReference(to: users)
    }
}

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
    let cell = self.collectionView.dequeueReusableCell(withReuseIdentifier: "MyCell", for: indexPath) as! UserViewCell

    let realm = try! Realm()
    guard let usersRef = usersRef, let users = realm.resolve(usersRef) else {return}
    let user = users[indexPath.row]
    cell.firstName.text = user.firstName
    cell.lastName.text = user.lastName
}