Reputation: 1184
I am creating an app that needs to save a counter variable (which is an integer) into the cloud when the app exits, then loads the counter when the app becomes active. Ive never used CloudKit before could someone simplify how i could do this using swift? many of the examples I've tried to replicate are too complex for what I am trying to achieve.
Note: Before anyone mentions it , I know there are other ways to achieve this but I want to do it using CloudKit.
Also, I already understand how appDelegate transitions work so i don't need help with that :)
Upvotes: 0
Views: 1177
Reputation: 8995
Matt, the reason you should do this another way is cause it is far simpler and will almost certainly be more reliable than cloud kit.
let defaults = NSUserDefaults.standardUserDefaults()
defaults.setInteger(yourInt, forKey: "blah")
Your got these options in swift ...
func setBool(value: Bool, forKey defaultName: String)
func setInteger(value: Int, forKey defaultName: String)
func setFloat(value: Float, forKey defaultName: String)
func setDouble(value: Double, forKey defaultName: String)
func setObject(value: AnyObject?, forKey defaultName: String)
func setURL(url: NSURL, forKey defaultName: String)
To fetch the value the next time
let defaults = NSUserDefaults.standardUserDefaults()
if let yourInt = defaults.integerForKey("blah")
{
print(yourInt)
}
You got a few more methods to get them back
func boolForKey(defaultName: String) -> Bool
func integerForKey(defaultName: String) -> Int
func floatForKey(defaultName: String) -> Float
func doubleForKey(defaultName: String) -> Double
func objectForKey(defaultName: String) -> AnyObject?
func URLForKey(defaultName: String) -> NSURL?
func dataForKey(defaultName: String) -> NSData?
func stringForKey(defaultName: String) -> String?
func stringArrayForKey(defaultName: String) -> [AnyObject]?
func arrayForKey(defaultName: String) -> [AnyObject]?
func dictionaryForKey(defaultName: String) -> [NSObject : AnyObject]?
And that is it; but wait, you want to use cloud kit... let me give you a second answer after I post this.
Upvotes: 0
Reputation: 8995
CloudKit: Ok lets do some planning and get out assumptions agreed.
Unclear as to the nature of what your really want to do here beyond writing a noddy method; lets assuming you want something a bit more.
enum CKErrorCode : Int {
case InternalError
case PartialFailure
case NetworkUnavailable
case NetworkFailure
case BadContainer
case ServiceUnavailable
case RequestRateLimited
case MissingEntitlement
case NotAuthenticated
case PermissionFailure
case UnknownItem
case InvalidArguments
case ResultsTruncated
case ServerRecordChanged
case ServerRejectedRequest
case AssetFileNotFound
case AssetFileModified
case IncompatibleVersion
case ConstraintViolation
case OperationCancelled
case ChangeTokenExpired
case BatchRequestFailed
case ZoneBusy
case BadDatabase
case QuotaExceeded
case ZoneNotFound
case LimitExceeded
case UserDeletedZone
}
OK, you saved it; what about next time. Ok its the same palaver, network, cloud kit, read, deal with errors etc etc.
If your still here, well done. Here the code just to save a record.
func save2Cloud(yourInt:Int) {
let container = CKContainer(identifier: "iCloud.blah")
let publicDB = container.publicCloudDatabase
let newRecord = CKRecord(recordType: "BlahBlah")
newRecord.setObject(yourInt, forKey: "theInt")
var localChanges:[CKRecord] = []
var recordIDsToDelete:[CKRecord] = []
localChanges.append(newRecord)
let saveRecordsOperation = CKModifyRecordsOperation(recordsToSave: localChanges, recordIDsToDelete: nil)
saveRecordsOperation.perRecordCompletionBlock = { record, error in
if error != nil {
self.showAlert(message: error!.localizedDescription)
print(error!.localizedDescription)
}
dispatch_async(dispatch_get_main_queue()) {
// give the UI a all good sign for that record
}
}
saveRecordsOperation.modifyRecordsCompletionBlock = { savedRecords, deletedRecordIDs, error in
if error != nil {
self.showAlert(message: error!.localizedDescription)
print(error!.localizedDescription)
} else {
dispatch_async(dispatch_get_main_queue()) {
// give the UI a all good sign for all records
}
}
}
saveRecordsOperation.qualityOfService = .Background
publicDB.addOperation(saveRecordsOperation)
}
And here the code to read it back.
var readerOperation: CKQueryOperation!
func read4Cloud(theLink: String, theCount: Int) {
var starCount:Int = 0
let container = CKContainer(identifier: "iCloud.blah")
let publicDB = container.publicCloudDatabase
let predicate = NSPredicate(value: true)
let query = CKQuery(recordType: "BlahBlah", predicate: predicate)
readerOperation = CKQueryOperation(query: query)
readerOperation.recordFetchedBlock = { (record) in
let YourInt = record["theInt"] as! Int
}
readerOperation.queryCompletionBlock = {(cursor, error) in
if error != nil {
// oh dingbats, you need to check for one of those errors
} else {
// got it
}
}
readerOperation.qualityOfService = .Background
publicDB.addOperation(readerOperation)
}
But wait Matt, this is going to save a new record everytime, and read back multiple Ints when you re-open. No this solution needs some more work; and I haven't done the network or the cloud check or any of the errors... :\
Disclaimer; I edited this code in SO, it may not compile cleanly :)
Upvotes: 5