Adam Altinkaya
Adam Altinkaya

Reputation: 639

Performing background save in Swift

I have several functions that look similar to below. They all run fine and complete normally. However, the below function doesn't ever seem to run the part where lineCount >= rows.count. The function just hangs. When I print out the lineCount, it sometimes displays the same number several times in a row. Am I doing something obviously wrong? What's even more bizarre, is that if I take out the 2nd part in each of the NSPredicates (i.e. the itemNumber) it works fine.

func populatePurchaseLine(json: JSONDictionary) -> Void {
    guard let rows = json["rows"] as? [JSONDictionary] else {
        return
    }
    var lineCount = 0
    persistentContainer!.performBackgroundTask { (context) in
        for row in rows {
            guard let action = row["action"] as? String else {
                return
            }

            if (action == "A") || (action == "C") {
                // add
                guard let aRecord = row["data"] as? JSONDictionary else {
                    return
                }

                var recordToSave: MyTable

                if let popNo = aRecord["AKey"] as? NSNumber, let lineNumber = aRecord["AnotherKey"] as? NSNumber {
                    let predicate = NSPredicate(format: "aNumberField == \(popNo.int64Value) AND itemNumber == \(lineNumber.int64Value)")
                    let result = DatabaseHelper.fetchRecordsForEntity(entity: "MyTable",
                                                                      managedObjectContext: context,
                                                                      predicate: predicate) as! [MyTable]

                    if result.isEmpty {
                        recordToSave = MyTable(context: context)
                    } else {
                        recordToSave = result.first!
                    }
                } else {
                    recordToSave = MyTable(context: context)
                }

                if let popNo = aRecord["AKey"] as? NSNumber {
                    recordToSave.aNumberField = popNo.int64Value
                }

                if let anItem = aRecord["AnotherKey"] as? NSNumber {
                    recordToSave.itemNumber = anItem.int64Value

                do {
                    try context.save()
                    lineCount += 1
                    if (lineCount >= rows.count) {
                        if self.hasCancelled {
                            self.abortDownload()
                        } else {
                            self.downloadStage = .downloadNextOne
                            self.startDownloadViaCloud(fileName: nil)
                        }
                    }
                } catch {
                    print("Failure to save context: \(error)")
                }
            } else if action == "D" {
                guard let theData = row["data"] as? JSONDictionary else {
                    return
                }
                guard let popNo = theData["AKey"] as? NSNumber else {
                    return
                }
                guard let lineNumber = theData["AnotherKey"] as? NSNumber else {
                    return
                }
                self.persistentContainer!.performBackgroundTask { (context) in
                    let predicate = NSPredicate(format: "aNumberField == \(popNo.int64Value) AND itemNumber == \(lineNumber.int64Value)")

                    let result = DatabaseHelper.fetchRecordsForEntity(entity: "MyTable",
                                                                      managedObjectContext: context,
                                                                      predicate: predicate) as! [MyTable]

                    if let theLine = result.first {
                        context.delete(theLine)
                    }

                    do {
                        try context.save()
                        lineCount += 1
                        if (lineCount >= rows.count) {
                            if self.hasCancelled {
                                self.abortDownload()
                            } else {
                                self.downloadStage = .downloadNextOne
                                self.startDownloadViaCloud(fileName: nil)
                            }
                        }
                    } catch {
                        print("Failure to save context: \(error.localizedDescription)")
                    }
                }
            }
        }
    }
}

Upvotes: 0

Views: 98

Answers (1)

Tomas Jablonskis
Tomas Jablonskis

Reputation: 4376

Do not create predicates as strings, that is bound to fail in any but trivial cases which is probably your problem here. Create the predicate as follows:

NSPredicate(format: "(aNumberField == %@) AND (itemNumber == %@)", popNo.int64Value, lineNumber.int64Value)

or use compound predicate:

NSCompoundPredicate(
    type: .and,
    subpredicates: [
        NSPredicate(format: "aNumberField == %@", popNo.int64Value),
        NSPredicate(format: "itemNumber == %@", lineNumber.int64Value)
    ]
)


P.S. do not forget () brackets in predicate with several conditions.
Good luck :)

Upvotes: 1

Related Questions