与Realm结合执行异步串行请求的问题

时间:2016-10-06 14:41:02

标签: swift multithreading asynchronous realm

我想与Realm一起执行一组串行异步请求。

我想要处理的请求集用于更新远程服务器,并由包含对象类型和本地uuid的结构数组确定。从Realm数据库获取相关对象,然后使用Alamofire将其写入服务器。

但是,获取Realm对象会导致错误(Realm accessed from incorrect thread)。

func performAsyncRequest<T: Object>(objectType: T.Type, uuid: String, failure fail: (()->Void)? = nil, success succeed: @escaping () -> Void)->Void {

    let realm = try! Realm() 
    let dataObject = realm.objects(objectType).filter("uuid == %@", uuid).first!
    let parameters = self.toJson(item: dataObject)

    // ** The Realm error occurs when the Alamofire request is performed  **

    let urlRequest = self.getRequest(objectType: T.self, with: parameters) 
    self.alamoFireManager.request(urlRequest) // Perform POST request
        .responseString { response in
            if let status = response.response?.statusCode {
                if status >= 200 && status <= 299 {
                    succeed() // Is not reached in combination with DispatchSemaphore
                } else if status >= 400 && status <= 499 {
                    fail?() // Is not reached in combination with DispatchSemaphore
                }
            }
    }
}

编辑:在下面的答案之后编辑以下代码(其中解决了串行Alamofire请求的先前问题)。

为了连续执行Alamofire请求,OperationQueueDispatchSemaphore结合使用。

    let operationQueue = OperationQueue()
    var operation: Operation!

    for requestData in requests { // requestData is a struct with the object Type and a uuid
        switch requestData.objectType {
            case is Object1.Type:
                operation = BlockOperation(block: {
                    let semaphore = DispatchSemaphore(value: 0)
                    self.performAsyncRequest(objectType: Object1.self, uuid: requestData.uuid, failure: { error in
                           semaphore.signal()
                       }) {
                       semaphore.signal()
                    }
                    semaphore.wait()
                })
            case is Object2.Type:
                    // ... same as for Object1 but now for Object2

            // .. and so on for other Objects                
            }
        operationQueue.addOperation(operation)
    }

如下面的答案所示,错误发生是因为Realm是线程限制的。但是,我不清楚为什么Realm实例会通过不同的线程传递。

使用异常断点我确定错误发生在线程Queue: NSOperationQueue 0x… (QOS: UTILITY) (serial)上。这是执行BlockOperation的不同线程(因此获取Realm对象的位置)。为什么BlockOperation内的方法不在与NSOperationQueue相同的线程上执行?

我很感激处理这些问题的任何想法。

1 个答案:

答案 0 :(得分:0)

Realm和Realm对象是线程限制。您应该在每个线程上检索新的realm实例。不要跨其他线程传递Realm实例。

似乎主线程因等待信号量而停止。然后在主线程上执行Alamofire回调。因此,semaphore.signal()永远不会被调用,因为主线程停止了。 Alamofire的response*方法可以指定调用回调queue