0
votes

I want to get a sequential invoice number from iCloud using CloudKit, Swift 4.2+ and iOS 11+.

I have never done this with iCloud. Not sure what is the best way to go.

This number will be written into a PDF document which will be saved back to the public iCloud database.

Predicates are limited. I don't think I can use max(number). Obviously no SQL options.

I'm thinking about using notifications to update each device when a number is used and store that locally. But can I trust that? Or do I create another server just to get a unique number?

Not sure if I can use a query with a limit of 1 and sorted by date and then prefill the records with potential numbers (see code below) or just have one record which is updated each time?

func getNextInvoiceNumber() {

    let predicate = NSPredicate(format: "status == %@", "unused")
    let query = CKQuery(recordType: "Sequence", predicate: predicate)
    query.sortDescriptors = [NSSortDescriptor(key: "sequenceNumber", ascending: true)]

    let operation = CKQueryOperation(query: query)
    operation.resultsLimit = 1
    operation.recordFetchedBlock = { (record) in

        DispatchQueue.main.async {
            let invoiceNumber = record["sequenceNumber"]
            // Update the Record so that it is not used again using CKModifyRecordsOperation
            record["status"] = "used" // do I also set recordName because it must be unique?
            // save this record back to iCloud so it can't be used again
            // if I can save it successfully I can use it
            self.saveUsedInvoiceNumber(record: record) // will need to retry this in case someone got this number before my save
            // Write a valid invoiceNumber to the PDF
            self.addInvoiceNumberToDocument(number: invoiceNumber as! Double) // prob move to completion handler from above
        }

    }
    CKContainer.default().publicCloudDatabase.add(operation)
}

func saveUsedInvoiceNumber(record: CKRecord) {
    // CKModifyRecordsOperation(...)
    //

}

func addInvoiceNumberToDocument(number: Double) {
    // write invoice Number to the PDF file and save to disk
    // save PDF file to iCloud
}

I am mindful of the potential for conflict with multiple transactions and concurrent users.

Any suggestions on ways you've handled this in iCloud?

2

2 Answers

0
votes

Here, way you suggested will work if not offline requirement. You should use one record instead of array. Array will increase size day by day and may be create issue in fetch time.

0
votes

Every record in iCloud has a unique ID. Why not use that as your invoice number, it shouldn't change unless you delete and recreate your record. You get that for free.