2016-12-16 8 views
0

3つの並行キューが実行されているDispatchグループを作成し、グループに更新の通知を行いました。私が直面しているのは完了ハンドラです。キューの実行が完了する前に呼び出されます。これを解決できますか、アドバイスをお願いしますか?CompletionハンドラがDispatch GroupとConcurrent Queueで期待どおりに動作しない

func loadCompaniesFromSynch(_ data: Data, completionHandler: @escaping(String) ->()) 
{ 

    var companyFile = "" 
    companies = [Company]() 
    let batchGroup = DispatchGroup() 
    let queue = DispatchQueue(label: "Batch Queue", qos: .background, attributes: .concurrent) 

    if !FileManager.default.fileExists(atPath: self.fileMgr.getDocumentPath()) { 
     self.fileMgr.createFileDirectory(self.constants!.APP_FOLDER) 
    } 

    companyFile = self.fileMgr.getDocumentFilePath(self.fileMgr.getCacheData(constants!.COMPANIES_LAST_SYNCH_DATE) as! String) 
    let dataOld: Data = try! Data(contentsOf: URL(fileURLWithPath: companyFile),options: NSData.ReadingOptions.uncached) 

    let oldCompanies: NSArray! = (try? JSONSerialization.jsonObject(with: dataOld, options: JSONSerialization.ReadingOptions.mutableContainers)) as? [[String:Any]] as NSArray! 

    let newCompanyObj: NSDictionary? = (try? JSONSerialization.jsonObject(with: data, options: JSONSerialization.ReadingOptions.mutableContainers)) as? NSDictionary 

    var company: Company? 

    if newCompanyObj?.count > 0 { 

     if let companies = oldCompanies 
     { 
      for com in companies as! [[String: AnyObject]] 
      { 

       company = Company() 
       company!.orgCode = com["ORG_CODE"] as? String 
       company!.orgDescription = com["ORG_DESCRIPTION"] as? String 

       if let btlOrg = com["OBX_BTL_CODE"] as? String 
       { 
        company!.orgBtlCode = btlOrg 
        company!.orgBtlDescription = com["BTL_DESCRIPTION"] as? String 
       } 
       company!.orgStatus = com["ORG_STATUS"] as! String? 

       self.companies!.append(company!) 
       company = nil 
      } 



     } 

    print("loadCompaniesFromSynch >> oldCompanies >>\(oldCompanies.count) Comapnies Count \(self.companies!.count)") 

     var dataDict = Dictionary<String,String>() 

     if let json = newCompanyObj as NSDictionary! 
     { 
      if let companies = json["RESULTS"] as? NSDictionary 
      { 
       if let companiesNew = companies["COMPANIES"] as? [[String: AnyObject]] 
       { 
        // for com in companiesNew 

        let addArray = companiesNew.filter { $0["ORG_STATUS"] as! String == ComapnyStatus.ADD.rawValue} 
        let deleteArray = companiesNew.filter { $0["ORG_STATUS"] as! String == ComapnyStatus.DELETED.rawValue} 
        let updateArray = companiesNew.filter { $0["ORG_STATUS"] as! String == ComapnyStatus.UPDATE.rawValue} 

        print(addArray.count) 
        print(deleteArray.count) 
        print(updateArray.count) 



        var addCompanies: [Company]? 
        var updateCompanies:[Company]? 
        var comapnySet = Set(self.companies!) 


        batchGroup.enter() 
        queue.async(group: batchGroup) 
        { 
         if (addArray.count > 0) 
         { 
          addCompanies = [Company]() 
          for (index,item) in addArray.enumerated() 
          { 

           let company =  self.returnComapnyOjectfromDictionary(item as NSDictionary) 
           addCompanies!.append(company) 
           print("add loop----\(index)") 
          } 

         } 
         batchGroup.leave() 

        } 

        batchGroup.enter() 
        queue.async(group: batchGroup) { 

         if updateArray.count > 0 
         { 
          updateCompanies = [Company]() 


         for (index,item) in updateArray.enumerated() 
         { 
          let company = self.returnComapnyOjectfromDictionary(item as NSDictionary) 
          updateCompanies!.append(company) 
           print("update loop----\(index)") 

         } 
         } 
         batchGroup.leave() 
        } 

        batchGroup.enter() 
        queue.async(group: batchGroup) { 

         for (_,item) in deleteArray.enumerated() 
         { 

          let company = self.returnComapnyOjectfromDictionary(item as NSDictionary) 
          _ = self.removeObject(&self.companies!,object: company) 
          print("looop2") 

         } 

         batchGroup.leave() 
        } 


        batchGroup.notify(queue: .global(qos: .background)) 
        { 

         if updateCompanies?.count == updateArray.count{ 

          //self.companies = Array(comapnySet) 
          print("count before \(self.companies?.count)") 

          comapnySet.subtract(Set(updateCompanies!)) 
          self.companies = Array(comapnySet) 

          // self.companies = Array(comapnySet.intersection(Set(updateCompanies!))) 
          print("after delete \(self.companies?.count)") 

          self.companies!.append(contentsOf: updateCompanies!) 


          print("update array count \(updateArray.count) ----- and update Companies count --\(self.companies?.count)") 
          updateCompanies = nil 

         } 
         if addCompanies?.count == addArray.count 
         { 
         self.companies!.append(contentsOf: addCompanies!) 
          print("add array count \(addArray.count) ----- and add Companies count --\(addCompanies?.count)") 

          addCompanies = nil 
         } 

        } 

        batchGroup.wait() 
       } 
      } 

//**Below code is executed before queue completion** 
      if let status = json["STATUS"] as? String 
      { 
       dataDict[self.constants!.defaultsKeys.RESPONSE_STATUS]  = status 
      } 
      if let message = json["MESSAGE"] as? String 
      { 
       dataDict[self.constants!.defaultsKeys.RESPONSE_MESSAGE] = message 
      } 
     } 

     var newCompanyArray:Array<AnyObject> = [] 
     var dict = Dictionary<String,String>() 


     for cmp in self.companies! 
     { 
      dict["ORG_CODE"] = cmp.orgCode 
      dict["ORG_DESCRIPTION"] = cmp.orgDescription 
      dict["OBX_BTL_CODE"] = cmp.orgBtlCode 
      dict["BTL_DESCRIPTION"] = cmp.orgBtlDescription 
      dict["ORG_STATUS"] = cmp.orgStatus 

      newCompanyArray.append(dict as AnyObject) 
     } 

     let isValidJson = JSONSerialization.isValidJSONObject(newCompanyArray) 


     if newCompanyArray.count > 0 && isValidJson 
     { 
      let companyCount = newCompanyArray.count - oldCompanies.count 

      let replaceComCount = self.utility!.replace(self.constants!.logs.LOG_COMPANY_SYNC_END,originalString: "<COUNT>",withString: "\(companyCount)") 


      self.parser!.setLogValueToXml(replaceComCount, logType: 
       self.constants!.logs.LOG_TYPE_ACTIVITY, fileLogType: "") 


      let dataFinal:Data = try! JSONSerialization.data(withJSONObject: newCompanyArray, options: []) 
      self.fileMgr.removeFile(self.fileMgr.getDocumentFilePath(self.fileMgr.getCacheData(self.constants!.COMPANIES_LAST_SYNCH_DATE) as! String)) 
      let compniesFileName = "Companies_\(self.dateUtil.getCurrentDateTime())" //logic is to be use in synch 
      self.fileMgr.setCacheData(compniesFileName as AnyObject, key: self.constants!.COMPANIES_LAST_SYNCH_DATE) 

      self.fileMgr.writeFile(NSString(data: dataFinal, encoding: String.Encoding.utf8.rawValue)!,fileName :self.fileMgr.getCacheData(self.constants!.COMPANIES_LAST_SYNCH_DATE) as! String,documentDir:self.fileMgr.getDocumentPath()) 

     } 

    } 

    completionHandler(companyFile) 
} 
DispatchQueue.global(qos: .background).async 
           { 
            self.loadCompaniesFromSynch(jNsData, completionHandler: 
            { 
             companyFile in 

              if !companyFile.isEmpty 
              { 
              self.doPropertySync() 
              } 
              else 
              { 

              } 
            }) 
           } 
+0

コードを 'notify'クロージャの中に入れなければなりません。 – shallowThought

+0

@shallowThought - 試しましたが、これはうまくいかないようです。 –

答えて

0

あなたは多くのことを混ぜています。あなたは通知を受けようとしていますが、あなたも待っています。

キュー完了」

...あなたの通知ブロック外で実行されている/と呼ばれる前に、あなたの completion()ハンドラとコードの下

// でマークされたコードが実行される

AFAICSの場合、notifyまたはwaitloadCompaniesFromSynch()を使用する理由はありません。asynそれの中のcタスク。

あなたがしたいことは、あなたの重いioの事をバックグラウンドで行うことです。この場合、DispatchGroupのものをすべて削除し、穴の機能をディスパッチしてください。完了ハンドラを使用しているときに、待機/通知する必要はありません。アイデアを得るには、以下を確認してください。

func loadCompaniesFromSynch(_ data: Data, completionHandler: @escaping(String) ->()) { 
    // dispatch the whole thing to the global background queue 
    DispatchQueue.global(qos: .background).async { 

     // your original code with all DispatchGroup stuff deleted 

     // call completion handler on main queue, so the caller does not have to care 
     DispatchQueue.main.async { 
      completionHandler(companyFile) 
     }   
    } 
} 

self.loadCompaniesFromSynch(jNsData) { 
    companyFile in 

    // do stuff after loadCompaniesFromSynch finished 
} 

希望します。

+0

@ shallowThought-上記のソリューションは完璧ですが、私の親forループの長さは約133500です。したがって、これを並列実行して時間を短縮したいのですが、これを達成するためのより良い解決法はありますか? –

+0

今は30分以上かかります。 –

+0

あなたは "parent for loop"を参照していますか? – shallowThought

関連する問題