Can't fetch userCKRecordID with Swift - ios

I am getting the error: "Value of type 'CKDatabase' has no member 'fetchUserRecordIDWithCompletionHandler'." Was it taken out of the newest version of Xcode or swift 3?
func fetchUserRecords()
{
let publicDB = CKContainer.default().publicCloudDatabase
publicDB.fetchUserRecordIDWithCompletionHandler { (userID, error) -> Void in
if let userID = userID {
let reference = CKReference(recordID: userID, action: .None)
let predicate = NSPredicate(format: "creatorUserRecordID == %#", reference)
let query = CKQuery(recordType: "Location", predicate: predicate)
CKContainer.default().publicCloudDatabase.perform(query, inZoneWith: nil){
(records, error) in
if error != nil {
print("error fetching user records: \(error)")
completion(error as NSError?, nil)
} else {
print("found user records")
completion(nil, records)
guard let records = records else {
return
}
for record in records
{
//delete records
}
}
}
}
}
}

Swift 3 changes the names of lots of function calls. The new function signature is
func fetchUserRecordID(completionHandler: #escaping (CKRecordID?, Error?) -> Void)
EDIT:
rmaddy reports that the function is a function of CKContainer, not CKDatabase.

Related

How to use query to fetch cloudkit data in swift

I am trying to have all the users' locations stored in cloudkit, then downloaded by each device. I marked on the code in storeLocation where I get the error:
"Cannot convert value of type '(NSError?, [CKRecord]?)' (aka '(Optional, Optional>)') to expected argument type '(error: NSError?, records: [CKRecord]?) -> Void'"
//saves location in cloud kit //currently works well:
var locArray = [CKRecord]()
func storeLocation(location:CLLocation) {
let locationRecord = CKRecord(recordType: "location")
locationRecord.setObject(location, forKey: "location")
let publicData = CKContainer.defaultContainer().publicCloudDatabase
publicData.saveRecord(locationRecord) { (records, error) in
if error != nil {
print("error saving locations: \(error)")
} else {
print("Locations saved: \(records)")
loadLocation((error, self.locArray)) //where I get error******
}
}
}
//fetches location from cloud kit:
func loadLocation(completion: (error:NSError?, records:[CKRecord]?) -> Void)
{
let query = CKQuery(recordType: "Location", predicate: NSPredicate(value: true))
CKContainer.defaultContainer().publicCloudDatabase.performQuery(query, inZoneWithID: nil){
(records, error) in
if error != nil {
print("error fetching locations")
completion(error: error, records: nil)
} else {
print("found locations: \(records)")
completion(error: nil, records: records)
}
}
}
I believe instead of:
loadLocation((error, self.locArray))
You need to call this:
loadLocation() { (error, records) in
// do something here with the returned data.
}

How to download multiple records from cloudkit

I am trying to download multiple items from cloud kit but I'm getting the error "cannot assign type value (CKQueryCursor!, NSError) -> () to type (CKQueryCursor?, NSError?) -> void"
let locationToLookFor = CLLocation()
let predicate = NSPredicate(format: "location = %#", locationToLookFor as CLLocation)
let query = CKQuery(recordType: "Location", predicate: predicate)
let operation = CKQueryOperation(query: query)
operation.recordFetchedBlock = self.recordFetchBlock
operation.queryCompletionBlock =
{
[weak self]
(cursor: CKQueryCursor!, error: NSError) in
if(cursor != nil)
{
print("Fetching records")
let newOperation = CKQueryOperation(cursor: cursor)
operation.recordFetchedBlock = recordFetchBlock
operation.queryCompletionBlock = operation.queryCompletionBlock
self!.operationQueue.addOperation(newOperation)
}
else {
print("We have fetched all data")
}
}
operationQueue.addOperation(operation)
Your closure signature doesn't match the required signature. As shown in the error message, cursor should be optional as should error. You will also get an error because you don't unwrap cursor when you supply it to the new operation.
Try:
operation.queryCompletionBlock =
{
[weak self]
(cursor: CKQueryCursor?, error: NSError?) -> Void in
if let cursor = cursor
{
print("Fetching records")
let newOperation = CKQueryOperation(cursor: cursor)
operation.recordFetchedBlock = recordFetchBlock
operation.queryCompletionBlock = operation.queryCompletionBlock
self?.operationQueue.addOperation(newOperation)
}
else {
print("We have fetched all data")
}
}

How do I query and obtain data from CloudKit?

I am fairly new to Swift, and just started learning about CloudKit this week for an iOS app project.
The database is working, I can add records and find records in the database.
I have run into a problem sending a query to CloudKit and accessing the data related to the query.
The CloudKit data has unique identifiers, so the search is for one of those identifiers (so a query should only return one record). I am then trying to obtain three pieces of information from that record - "UPC", "foodName", and "Ingredients" (all strings)
Here is the code section that executes the query and tries to obtain the data.
let publicDatabase = CKContainer.defaultContainer().publicCloudDatabase
let predicate = NSPredicate(format: "UPC = %#", subStr)
let query = CKQuery(recordType: "Food", predicate: predicate)
publicDatabase.performQuery(query, inZoneWithID: nil,
completionHandler: ({results, error in
if (error != nil) {
dispatch_async(dispatch_get_main_queue()) {
print("CloudKit Error")
}
} else {
if results!.count > 0 {
var record = results as! CKRecord
dispatch_async(dispatch_get_main_queue()) {
print("UPC Found")
let cloudUPC = record.objectForKey("UPC") as! CKAsset
print("UPC from CloudKit \(cloudUPC)")
}
} else {
dispatch_async(dispatch_get_main_queue()) {
print("UPC Not Found")
}
}
}
}))
The crash occurs at this point
var record = results as! CKRecord
and returns "EXC_Breakpoint(code = 1, subcode - 0x10047b7c)
Any suggestions on how to solve this problem?
Thanks
Thank you for the suggestion rmaddy.
This is how I fixed the code
let publicDatabase = CKContainer.defaultContainer().publicCloudDatabase
let predicate = NSPredicate(format: "UPC = %#", subStr)
let query = CKQuery(recordType: "Food", predicate: predicate)
publicDatabase.performQuery(query, inZoneWithID: nil,
completionHandler: ({results, error in
if (error != nil) {
dispatch_async(dispatch_get_main_queue()) {
print("Cloud Error")
}
} else {
if results!.count > 0 {
dispatch_async(dispatch_get_main_queue()) {
for entry in results! {
let cloudUPC = entry["UPC"] as? String
print("UPC from CloudKit \(cloudUPC)")
let cloudFoodName = entry["foodName"] as? String
print("Name from CloudKit \(cloudFoodName)")
let cloudIngredients = entry["Ingredients"] as? String
print("Ingredients from CloudKit \(cloudIngredients)")
}
} else {
dispatch_async(dispatch_get_main_queue()) {
print("UPC Not Found")
}
}
}
}))
you need to first to write for loop on items in record then print each UPC
like that :
for item in record {
print(item["UPC"]
print(item["foodName"]
}

CloudKit saveRecord Complete

I am using the code below to update a record. Once the record has been updated I would like to run my refresh function. At the moment the refresh function is sometimes called before the record has been updated so the refresh results are the same as before the record was updated.
Thanks
var tempDocumentsArray:NSArray!
let recordID = CKRecordID(recordName: "layerAbove")
var predicate = NSPredicate(format: "recordID = %#", recordID)
let query = CKQuery(recordType: "Layers", predicate: predicate)
self.publicDB.performQuery(query, inZoneWithID: nil) { (results, error) -> Void in
tempDocumentsArray = results
print("Results are: \(tempDocumentsArray)")
let record = tempDocumentsArray[0] as! CKRecord
var layerAbovePrevPos = record.objectForKey("layerNumber") as! Int
layerAbovePrevPos = layerAbovePrevPos - 1
let nlnChanged = record.setObject(layerAbovePrevPos, forKey: "layerNumber")
self.publicDB.saveRecord(record, completionHandler: { (returnRecord, error) -> Void in
if let err = error {
print("Error: \(err.localizedDescription)")
} else {
dispatch_async(dispatch_get_main_queue()) {
print("Success")
//TODO:This is sometimes called before the save is complete!
self.resetAndGet()
}
}
})
}

Fetch records with CloudKit in Swift

i try to fetch records with CloudKit. I use the example from Apple.
I can save records but i can't get them..
Here's the code to fetch the records saved :
func fetchRecords(completionHandler: ((NSArray!) -> Void)!) {
var predicate = NSPredicate(value: true)
var query = CKQuery(recordType: "type", predicate: predicate)
/*self.publicDatabase.performQuery(query, inZoneWithID: nil, { (results:[AnyObject]!, error:NSError!) -> Void in
if (error){
println("An error occured in \(NSStringFromSelector(__FUNCTION__)) \(error)");
} else {
completionHandler(results)
}
})*/
var operation = CKQueryOperation(query: query)
var results = NSMutableArray()
operation.recordFetchedBlock = { (record:CKRecord!) -> Void in
results.addObject(record)
}
operation.queryCompletionBlock = { (cursor:CKQueryCursor!, error:NSError!) -> Void in
dispatch_async(dispatch_get_main_queue(), { () -> Void in
if (error) {
// Error Code 11 - Unknown Item: did not find required record type
if (error.code == 11) {
// Since schema is missing, create the schema with demo records and return results
}
else {
// In your app, this error needs love and care.
println("An error occured in \(NSStringFromSelector(__FUNCTION__)): \(error)");
abort();
}
} else {
completionHandler(results)
}
})
}
self.publicDatabase.addOperation(operation)
}
When i run this the "abort()" is called and i get this in the console :
An error occured in fetchRecords:
Thanks for helping guys.
I think the problem is with the way you are creating your predicate. The column/attribute that you want to query on is not specified.
Instead of:
var predicate = NSPredicate(value: true)
you should do something along the lines of:
var predicate = NSPredicate(format: "someColumn == true")
Try replacing
if (error)
with
if (error != nil)

Resources