Reputation: 259
i've created a Dispatch group in which three concurrent queues are running and then notifies group for update, which is going good and all this i've put in a function with completion handler.now issue i'm facing is completion handler get called before queue execution completes .how can i resolve this, please advice?
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
{
}
})
}
Upvotes: 2
Views: 870
Reputation: 19602
You are mixing up a lot of things. You are trying to get notified, but also you are trying to wait.
Your completion()
handler and the code marked with
//Below code is executed before queue completion"
is called/running outside your notification block...
AFAICS, there is no reason to use notify
or wait
whithin loadCompaniesFromSynch()
, as you do do not call any async tasks in it.
How I understand, what you want to do is to do your heavy io stuff in the background. In this case, delete all the DispatchGroup
stuff and dispatch the hole function. No need to wait/notify, as you are using a completion handler. Check the following to get the idea:
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
}
Hope this helps.
Upvotes: 2