ios - 在操作 block 中具有单独的Realm实例时,“从错误的线程访问了Realm”

标签 ios objective-c realm

我在单独的后台操作中更新领域对象,并在操作块本身中创建了Realm实例,但仍然收到此错误。有什么线索吗?

- (void)didFavoriteButtonTapped:(FlickerPhotoCell *)photoCell {

NSIndexPath *indexPath = [self.collectionView indexPathForCell:photoCell];
FlickerPhoto *photo = [self.photos objectAtIndex:indexPath.item];
photoCell.photoFavouriteButton.selected = !photo.isFavorited;

[self.opQueue addOperationWithBlock:^{

    RLMRealm *realm = [RLMRealm defaultRealm];
    [realm beginWriteTransaction];
    photo.isFavorited = !photo.isFavorited;
    [realm commitWriteTransaction];

    //Saving in local database
    NSPredicate *pred = [NSPredicate predicateWithFormat:@"photoURL == %@ AND isFavorited == YES", photo.photoURL];
    RLMResults *searchedPhotos = [FlickerPhoto objectsWithPredicate:pred];
    FlickerPhoto *photoInDatabase = [searchedPhotos firstObject];
    BOOL isPhotoExists = (photoInDatabase != nil);

    if(photo.isFavorited) {
        if(!isPhotoExists) {
            [realm transactionWithBlock:^{
                [realm addObject:photo];
            }];
        }
    } else {
        if(isPhotoExists) {
            [realm beginWriteTransaction];
            [realm deleteObject:photoInDatabase];
            [realm commitWriteTransaction];
        }
    }
}];

}

最佳答案

境界不安全。因此,只要您想写入Realm,它就必须与您创建对象的线程相同。
因此,在开始“addOperationWithBlock”操作之前,应该获取要访问的对象的唯一标识符,然后从该操作块中创建它。

因此,您可以执行以下三种选择之一:

  • 在同一线程上更新领域对象,顺便说一句,根据我的经验,这已经足够好了,领域写入事务并不是一项非常昂贵的任务。但这又取决于该调用的频率。
  • 在新线程中再次创建对象,并传递唯一的标识符而不是领域对象本身,然后在要写入的线程上重新创建它:
    - (void)didFavoriteButtonTapped:(FlickerPhotoCell *)photoCell {
    
    
     NSIndexPath *indexPath = [self.collectionView indexPathForCell:photoCell];
        FlickerPhoto *photo = [self.photos objectAtIndex:indexPath.item];
        NSString *photoUniqueIdentifier = photo.id // Getting I'ts identifier before opening a new thread 
        photoCell.photoFavouriteButton.selected = !photo.isFavorited;
    
        [self.opQueue addOperationWithBlock:^{
    
        FlickerPhoto *photoToUpdate = [FlickerPhoto objectForPrimaryKey:photoUniqueIdentifier]; // Getting the object again from the data base, in the new thread contex
    
        RLMRealm *realm = [RLMRealm defaultRealm];
        [realm beginWriteTransaction];
        photoToUpdate.isFavorited = !photoToUpdate.isFavorited;
        [realm commitWriteTransaction];
    
        //Saving in local database
        NSPredicate *pred = [NSPredicate predicateWithFormat:@"photoURL == %@ AND isFavorited == YES", photoToUpdate.photoURL];
        RLMResults *searchedPhotos = [FlickerPhoto objectsWithPredicate:pred];
        FlickerPhoto *photoInDatabase = [searchedPhotos firstObject];
        BOOL isPhotoExists = (photoInDatabase != nil);
    
        if(photoToUpdate.isFavorited) {
            if(!isPhotoExists) {
                [realm transactionWithBlock:^{
                    [realm addObject:photoToUpdate];
                }];
            }
        } else {
            if(isPhotoExists) {
                [realm beginWriteTransaction];
                [realm deleteObject:photoInDatabase];
                [realm commitWriteTransaction];
            }
        }
    }];
    

  • 或者您可以使用alloc init创建它,并手动设置I唯一标识符(不是写事务),然后可以从任何线程访问它,因为我还不是数据库对象。
  • 关于ios - 在操作 block 中具有单独的Realm实例时,“从错误的线程访问了Realm”,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38671379/

    相关文章:

    ios - 如何同时写入Realm的不同对象?

    ios - @testable import moduleName 不导入所有内容

    ios - 比较两个 NSDate 对象是否相同

    iphone - 多个 UIWebViews 问题

    ios - 删除 Realm 对象中的属性

    ios - 在 UITabBar 的选项卡之间传递数据

    ios - Xcode的Storyboard突然消失

    objective-c - 如何测试 NSUserDefaults 用户设置中是否存在 BOOL?

    ios - UICollectionView - 重新打开应用程序时未正确重绘

    android - 如何在同一个 Realm 查询中查询两个字段?