Here's my Model
import Cocoa
import CloudKit
@objc(LedgerAccount)
@objcMembers class LedgerAccount: NSObject {
var recordID: CKRecordID
var displayName: String
var ledgerType: String
var balance: Double
var balanceMetal: Double
var city: String
init(recordID: CKRecordID, displayName: String, ledgerType: String, balance: Double, balanceMetal: Double, city: String) {
self.recordID = recordID
self.displayName = displayName
self.ledgerType = ledgerType
self.balance = balance
self.balanceMetal = balanceMetal
self.city = city
}
}All records except city are from same LedgerAccount recordType in CloudKit.
The City record is from its Child recordType called LedgerAddresseses recordType.
Here's my API.
import Cocoa
import CloudKit
class ContactsAPI {
let privateData = CKContainer.default().privateCloudDatabase
let branch = CKRecordZone(zoneName: "Master")
var contacts: [LedgerAccount] = []
func fetchContacts(completionHandler: @escaping ([LedgerAccount]) -> Void) {
let contactsPredicate = NSPredicate(value: true)
let query = CKQuery(recordType: "LedgerAccount", predicate: contactsPredicate)
privateData.perform(query, inZoneWith: branch.zoneID) { [unowned self] (results, error) -> Void in
if error != nil {
print("Error: \(String(describing: error))")
} else {
DispatchQueue.main.async {
for result in results! {
let recordID = result["recordID"] as! CKRecordID
let displayName = result["DisplayName"] as! String
let ledgerType = result["LedgerType"] as! String
let balance = result["Balance"] as! Double
let balanceMetal = result["BalanceMetal"] as! Double
var city: String = ""
//fetching address
let addressPredicate = NSPredicate(format: "LedgerAccount = %@ && AddressLabel='Primary'", recordID)
let addressQuery = CKQuery(recordType: "LedgerAddresses", predicate: addressPredicate)
self.privateData.perform(addressQuery, inZoneWith: self.branch.zoneID) { (results, error) in
if error != nil {
} else {
for addressResult in results! {
city = addressResult["City"] as! String
print(city)
}
}
} // end of fetch addresses
print(city)
let contact = LedgerAccount(recordID: recordID,
displayName: displayName,
ledgerType: ledgerType,
balance: balance,
balanceMetal: balanceMetal,
city: city)
self.contacts.append(contact)
}
completionHandler(self.contacts)
}
}
}
} // end of fetchContacts
}At line 43, I get the city name, but at line 49 it returns null.
perform(_:inZoneWith:completionHandler:) Searches asynchronously.
If you need the city name in line 43 you need to use a Semaphore.
import Cocoa
import CloudKit
class ContactsAPI {
let privateData = CKContainer.default().privateCloudDatabase
let branch = CKRecordZone(zoneName: "Master")
var contacts: [LedgerAccount] = []
func fetchContacts(completionHandler: @escaping ([LedgerAccount]) -> Void) {
let contactsPredicate = NSPredicate(value: true)
let query = CKQuery(recordType: "LedgerAccount", predicate: contactsPredicate)
privateData.perform(query, inZoneWith: branch.zoneID) { [unowned self] (results, error) -> Void in
if error != nil {
print("Error: \(String(describing: error))")
} else {
DispatchQueue.main.async {
for result in results! {
let semaphore = DispatchSemaphore(value: 0)
let recordID = result["recordID"] as! CKRecordID
let displayName = result["DisplayName"] as! String
let ledgerType = result["LedgerType"] as! String
let balance = result["Balance"] as! Double
let balanceMetal = result["BalanceMetal"] as! Double
var city: String = ""
//fetching address
let addressPredicate = NSPredicate(format: "LedgerAccount = %@ && AddressLabel='Primary'", recordID)
let addressQuery = CKQuery(recordType: "LedgerAddresses", predicate: addressPredicate)
self.privateData.perform(addressQuery, inZoneWith: self.branch.zoneID) { (results, error) in
if error != nil {
} else {
for addressResult in results! {
city = addressResult["City"] as! String
print(city)
}
}
semaphore.signal()
} // end of fetch addresses
let _ = semaphore.wait(timeout: .distantFuture)
print(city)
let contact = LedgerAccount(recordID: recordID,
displayName: displayName,
ledgerType: ledgerType,
balance: balance,
balanceMetal: balanceMetal,
city: city)
self.contacts.append(contact)
}
completionHandler(self.contacts)
}
}
}
} // end of fetchContacts
}