我想与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请求,OperationQueue
与DispatchSemaphore
结合使用。
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
相同的线程上执行?
我很感激处理这些问题的任何想法。
答案 0 :(得分:0)
Realm和Realm对象是线程限制。您应该在每个线程上检索新的realm实例。不要跨其他线程传递Realm实例。
似乎主线程因等待信号量而停止。然后在主线程上执行Alamofire回调。因此,semaphore.signal()
永远不会被调用,因为主线程停止了。 Alamofire的response*
方法可以指定调用回调queue
。