2016-10-06 110 views
0

我想與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的同一線程上執行?

我將不勝感激任何想法來處理這些問題。

+0

rxSwift可以是一個更好的方法https://github.com/ReactiveX/RxSwift – StrawHara

+0

這是一個很好的建議,我通過所有文檔工作。但是,問題仍然是Realm是線程受限的,在使用RxSwift時也需要保證。 – Taco

+0

看看這個其他問題,我們可能在這裏有一個重複:http://stackoverflow.com/q/28646323/563802 – xpereta

回答

0

領域和領域對象是線程限制。您應該在每個線程上檢索新的領域實例。不要將Realm實例傳遞給其他線程。

似乎主線程因等待信號而停止。然後Alamofire回調在主線程上執行。所以semaphore.signal()永遠不會被調用,因爲主線程停止。 Alamofire的response*方法可以指定queue調用回調。

+0

我解決了第一個問題,通過在一個單獨的操作隊列上結合使用'OperationQueue'信號量,但我在獲取Realm方面仍存在問題。我確定Realm錯誤發生在線程'Queue:NSOperationQueue ...(QOS:UTILITY)(serial)'。但是,這與執行BlockOperation並從中獲取Realm對象的位置不同。你知道爲什麼'BlockOperation'裏的方法不是在同一個'NSOperationQueue'線程上執行的嗎?或者你知道在這種情況下如何確保線程限制?非常感謝... – Taco