the developer conference - cloudkit, entendendo a cloud da apple
TRANSCRIPT
![Page 1: The Developer Conference - CloudKit, entendendo a Cloud da Apple](https://reader031.vdocuments.site/reader031/viewer/2022030402/587b235c1a28ab736c8b70f9/html5/thumbnails/1.jpg)
Globalcode – Open4education
Trilha – iOSRodrigo Freitas Leite
iOS Developer
![Page 2: The Developer Conference - CloudKit, entendendo a Cloud da Apple](https://reader031.vdocuments.site/reader031/viewer/2022030402/587b235c1a28ab736c8b70f9/html5/thumbnails/2.jpg)
CloudKitEntendendo a cloud da Apple
![Page 6: The Developer Conference - CloudKit, entendendo a Cloud da Apple](https://reader031.vdocuments.site/reader031/viewer/2022030402/587b235c1a28ab736c8b70f9/html5/thumbnails/6.jpg)
What is Cloudkit ?
![Page 7: The Developer Conference - CloudKit, entendendo a Cloud da Apple](https://reader031.vdocuments.site/reader031/viewer/2022030402/587b235c1a28ab736c8b70f9/html5/thumbnails/7.jpg)
![Page 8: The Developer Conference - CloudKit, entendendo a Cloud da Apple](https://reader031.vdocuments.site/reader031/viewer/2022030402/587b235c1a28ab736c8b70f9/html5/thumbnails/8.jpg)
How do we start an app with CloudKit?
![Page 9: The Developer Conference - CloudKit, entendendo a Cloud da Apple](https://reader031.vdocuments.site/reader031/viewer/2022030402/587b235c1a28ab736c8b70f9/html5/thumbnails/9.jpg)
Register iCloud Container
![Page 10: The Developer Conference - CloudKit, entendendo a Cloud da Apple](https://reader031.vdocuments.site/reader031/viewer/2022030402/587b235c1a28ab736c8b70f9/html5/thumbnails/10.jpg)
![Page 11: The Developer Conference - CloudKit, entendendo a Cloud da Apple](https://reader031.vdocuments.site/reader031/viewer/2022030402/587b235c1a28ab736c8b70f9/html5/thumbnails/11.jpg)
Enable CloudKit Capability
![Page 12: The Developer Conference - CloudKit, entendendo a Cloud da Apple](https://reader031.vdocuments.site/reader031/viewer/2022030402/587b235c1a28ab736c8b70f9/html5/thumbnails/12.jpg)
![Page 13: The Developer Conference - CloudKit, entendendo a Cloud da Apple](https://reader031.vdocuments.site/reader031/viewer/2022030402/587b235c1a28ab736c8b70f9/html5/thumbnails/13.jpg)
CloudKit Dashboard
![Page 14: The Developer Conference - CloudKit, entendendo a Cloud da Apple](https://reader031.vdocuments.site/reader031/viewer/2022030402/587b235c1a28ab736c8b70f9/html5/thumbnails/14.jpg)
![Page 15: The Developer Conference - CloudKit, entendendo a Cloud da Apple](https://reader031.vdocuments.site/reader031/viewer/2022030402/587b235c1a28ab736c8b70f9/html5/thumbnails/15.jpg)
![Page 16: The Developer Conference - CloudKit, entendendo a Cloud da Apple](https://reader031.vdocuments.site/reader031/viewer/2022030402/587b235c1a28ab736c8b70f9/html5/thumbnails/16.jpg)
Record Type
![Page 17: The Developer Conference - CloudKit, entendendo a Cloud da Apple](https://reader031.vdocuments.site/reader031/viewer/2022030402/587b235c1a28ab736c8b70f9/html5/thumbnails/17.jpg)
Security Roles
![Page 18: The Developer Conference - CloudKit, entendendo a Cloud da Apple](https://reader031.vdocuments.site/reader031/viewer/2022030402/587b235c1a28ab736c8b70f9/html5/thumbnails/18.jpg)
Subscription Types
![Page 19: The Developer Conference - CloudKit, entendendo a Cloud da Apple](https://reader031.vdocuments.site/reader031/viewer/2022030402/587b235c1a28ab736c8b70f9/html5/thumbnails/19.jpg)
User Records
![Page 20: The Developer Conference - CloudKit, entendendo a Cloud da Apple](https://reader031.vdocuments.site/reader031/viewer/2022030402/587b235c1a28ab736c8b70f9/html5/thumbnails/20.jpg)
Public Default Zone
![Page 21: The Developer Conference - CloudKit, entendendo a Cloud da Apple](https://reader031.vdocuments.site/reader031/viewer/2022030402/587b235c1a28ab736c8b70f9/html5/thumbnails/21.jpg)
Usage
![Page 22: The Developer Conference - CloudKit, entendendo a Cloud da Apple](https://reader031.vdocuments.site/reader031/viewer/2022030402/587b235c1a28ab736c8b70f9/html5/thumbnails/22.jpg)
Team
![Page 23: The Developer Conference - CloudKit, entendendo a Cloud da Apple](https://reader031.vdocuments.site/reader031/viewer/2022030402/587b235c1a28ab736c8b70f9/html5/thumbnails/23.jpg)
Deployment
![Page 24: The Developer Conference - CloudKit, entendendo a Cloud da Apple](https://reader031.vdocuments.site/reader031/viewer/2022030402/587b235c1a28ab736c8b70f9/html5/thumbnails/24.jpg)
CloudKit Objects
![Page 25: The Developer Conference - CloudKit, entendendo a Cloud da Apple](https://reader031.vdocuments.site/reader031/viewer/2022030402/587b235c1a28ab736c8b70f9/html5/thumbnails/25.jpg)
Container
CKContainerOne container per application - usual
CKContainer(identifier: containerName)CKContainer.defaultContainer()
ApplicationContainer
CloudKit
![Page 26: The Developer Conference - CloudKit, entendendo a Cloud da Apple](https://reader031.vdocuments.site/reader031/viewer/2022030402/587b235c1a28ab736c8b70f9/html5/thumbnails/26.jpg)
Database
CKDatabase
• Public• Private
• Every app access to at least one container. • Every container has two databases
![Page 27: The Developer Conference - CloudKit, entendendo a Cloud da Apple](https://reader031.vdocuments.site/reader031/viewer/2022030402/587b235c1a28ab736c8b70f9/html5/thumbnails/27.jpg)
Database
CKDatabase• Every app access to at least one container.
PublicPublic
Private
• Every container has two databases
![Page 28: The Developer Conference - CloudKit, entendendo a Cloud da Apple](https://reader031.vdocuments.site/reader031/viewer/2022030402/587b235c1a28ab736c8b70f9/html5/thumbnails/28.jpg)
Database
CKDatabase
Public PrivatePrivatePublic Private
let publicDatabase = CKContainer.defaultContainer().publicCloudDatabase
let privateDatabase = CKContainer.defaultContainer().privateCloudDatabase
• Every app access to at least one container. • Every container has two databases
![Page 29: The Developer Conference - CloudKit, entendendo a Cloud da Apple](https://reader031.vdocuments.site/reader031/viewer/2022030402/587b235c1a28ab736c8b70f9/html5/thumbnails/29.jpg)
Database
Public Private
Data Type Shared Data User’s Data
Account Required for writing Required
Quota Developer User
Default Permissions World Redable User readable
Editing Permissions Dashboard Rules N/A
![Page 30: The Developer Conference - CloudKit, entendendo a Cloud da Apple](https://reader031.vdocuments.site/reader031/viewer/2022030402/587b235c1a28ab736c8b70f9/html5/thumbnails/30.jpg)
Record
Public
Record Record Record
Record Record Record
![Page 31: The Developer Conference - CloudKit, entendendo a Cloud da Apple](https://reader031.vdocuments.site/reader031/viewer/2022030402/587b235c1a28ab736c8b70f9/html5/thumbnails/31.jpg)
CKRecord classRecord
Structured dataWraps key/values pairsMetadataRecord Values• String• NSNumber• NSDate• NSData• CLLocation• CKAsset• CKReference
Array of these types
![Page 32: The Developer Conference - CloudKit, entendendo a Cloud da Apple](https://reader031.vdocuments.site/reader031/viewer/2022030402/587b235c1a28ab736c8b70f9/html5/thumbnails/32.jpg)
let session = CKRecord(recordType: "Session") session["name"] = "Endentendo a Cloudkit da Apple" session["author"] = "Rodrigo Leite" session["start_date"] = NSDate()
Record
![Page 33: The Developer Conference - CloudKit, entendendo a Cloud da Apple](https://reader031.vdocuments.site/reader031/viewer/2022030402/587b235c1a28ab736c8b70f9/html5/thumbnails/33.jpg)
Record
class session: CKRecord{ func name() -> String?{ return self["name"] as? String } func author() -> String?{ return self["author"] as? String } .... }
• Subclassing
Apple Docs
![Page 34: The Developer Conference - CloudKit, entendendo a Cloud da Apple](https://reader031.vdocuments.site/reader031/viewer/2022030402/587b235c1a28ab736c8b70f9/html5/thumbnails/34.jpg)
Record
class Session: NSObject{ let record: CKRecord? var name: String?{ didSet{ record!["name"] = name } } var author: String?{ didSet{ record!["author"] = name } }
init(record: CKRecord){ self.record = record self.name = self.record!["name"] as? String self.author = self.record!["author"] as? String } }
Apple Docs
![Page 35: The Developer Conference - CloudKit, entendendo a Cloud da Apple](https://reader031.vdocuments.site/reader031/viewer/2022030402/587b235c1a28ab736c8b70f9/html5/thumbnails/35.jpg)
CKRecordZone class
RecordZone
Public
Record
Record
Record
Record
Record
Record
Default Zone Custom Zone
![Page 36: The Developer Conference - CloudKit, entendendo a Cloud da Apple](https://reader031.vdocuments.site/reader031/viewer/2022030402/587b235c1a28ab736c8b70f9/html5/thumbnails/36.jpg)
Record Identifier
public class CKRecord : NSObject, NSSecureCoding, NSCopying { /* These create the record in the default zone. */ public init(recordType: String) public init(recordType: String, recordID: CKRecordID) public init(recordType: String, zoneID: CKRecordZoneID) public var recordType: String { get } @NSCopying public var recordID: CKRecordID { get } /* Change tags are updated by the server to a unique value every time a record is modified. A different change tag necessarily means that the contents of the record are different. */ public var recordChangeTag: String? { get } /* This is a User Record recordID, identifying the user that created this record. */ @NSCopying public var creatorUserRecordID: CKRecordID? { get } @NSCopying public var creationDate: NSDate? { get } /* This is a User Record recordID, identifying the user that last modified this record. */ @NSCopying public var lastModifiedUserRecordID: CKRecordID? { get } @NSCopying public var modificationDate: NSDate? { get } ..
}
• The identifier of the record in the cloud kit
![Page 37: The Developer Conference - CloudKit, entendendo a Cloud da Apple](https://reader031.vdocuments.site/reader031/viewer/2022030402/587b235c1a28ab736c8b70f9/html5/thumbnails/37.jpg)
References
Public
SessionAttendee
Session
Attendee
Attendee
![Page 38: The Developer Conference - CloudKit, entendendo a Cloud da Apple](https://reader031.vdocuments.site/reader031/viewer/2022030402/587b235c1a28ab736c8b70f9/html5/thumbnails/38.jpg)
CKReference class
References
• Back Reference•Cascade Deletes
/* *** Record Types **** */ let session = CKRecord(recordType: "Session") let attendee = CKRecord(recordType: "Attendee")
/* *** Create Reference by Record *** */ let reference = CKReference(record: session, action: .DeleteSelf) attendee["session"] = reference
/* **** Create Reference by RecordID *** */ let recordID = CKRecordID(recordName: "Session") let referenceWithRecordID = CKReference(recordID: recordID, action: .DeleteSelf) attendee["session"] = reference
![Page 39: The Developer Conference - CloudKit, entendendo a Cloud da Apple](https://reader031.vdocuments.site/reader031/viewer/2022030402/587b235c1a28ab736c8b70f9/html5/thumbnails/39.jpg)
Assets
Public
Record
Record
Asset
![Page 40: The Developer Conference - CloudKit, entendendo a Cloud da Apple](https://reader031.vdocuments.site/reader031/viewer/2022030402/587b235c1a28ab736c8b70f9/html5/thumbnails/40.jpg)
Assets
Record
Record
Public Bulk Storage
Asset
![Page 41: The Developer Conference - CloudKit, entendendo a Cloud da Apple](https://reader031.vdocuments.site/reader031/viewer/2022030402/587b235c1a28ab736c8b70f9/html5/thumbnails/41.jpg)
Assets
• CKAsset class• Large, unstructured data • Files on disk• Owned by records• Removed when owner is deleted
let attendee = CKRecord(recordType: "Attendee") let image = UIImage(named: "")! let documentDirectory = NSSearchPathForDirectoriesInDomains(.DocumentDirectory,
.UserDomainMask, true).first! as String
let localPath = documentDirectory + "/profilePicture" let data = UIImageJPEGRepresentation(image, 0.85) data!.writeToFile(localPath, atomically: true) let photoURL = NSURL(fileURLWithPath: localPath) let asset = CKAsset(fileURL: photoURL) attendee["profileImage"] = asset
![Page 42: The Developer Conference - CloudKit, entendendo a Cloud da Apple](https://reader031.vdocuments.site/reader031/viewer/2022030402/587b235c1a28ab736c8b70f9/html5/thumbnails/42.jpg)
Login
![Page 43: The Developer Conference - CloudKit, entendendo a Cloud da Apple](https://reader031.vdocuments.site/reader031/viewer/2022030402/587b235c1a28ab736c8b70f9/html5/thumbnails/43.jpg)
Login
CKContainer.defaultContainer().accountStatusWithCompletionHandler { (status: CKAccountStatus, error: NSError?) in switch status{ case .Available: print("Account is available") case .Restricted: print("Parental control or restriction") case .NoAccount: print("No account provide ") case .CouldNotDetermine: print("No account provide ") }
![Page 44: The Developer Conference - CloudKit, entendendo a Cloud da Apple](https://reader031.vdocuments.site/reader031/viewer/2022030402/587b235c1a28ab736c8b70f9/html5/thumbnails/44.jpg)
Convenience API
![Page 45: The Developer Conference - CloudKit, entendendo a Cloud da Apple](https://reader031.vdocuments.site/reader031/viewer/2022030402/587b235c1a28ab736c8b70f9/html5/thumbnails/45.jpg)
extension CKDatabase { /* Convenience APIs These calls operate on a single item in the default zone and allow for simple operations. If you'd like to batch your requests, add dependencies between requests, set priorities, or schedule operations on your own queue, take a look at the corresponding CKOperation. This work is treated as having NSQualityOfServiceUserInitiated quality of service. */ /* CKFetchRecordsOperation and CKModifyRecordsOperation are the more configurable, CKOperation-based alternatives to these methods */ public func fetchRecordWithID(recordID: CKRecordID, completionHandler: (CKRecord?, NSError?) -> Void) public func saveRecord(record: CKRecord, completionHandler: (CKRecord?, NSError?) -> Void) public func deleteRecordWithID(recordID: CKRecordID, completionHandler: (CKRecordID?, NSError?) -> Void) /* CKQueryOperation is the more configurable, CKOperation-based alternative to this method */ public func performQuery(query: CKQuery, inZoneWithID zoneID: CKRecordZoneID?, completionHandler: ([CKRecord]?, NSError?) -> Void) /* CKFetchRecordZonesOperation and CKModifyRecordZonesOperation are the more configurable, CKOperation-based alternatives to these methods */ public func fetchAllRecordZonesWithCompletionHandler(completionHandler: ([CKRecordZone]?, NSError?) -> Void) public func fetchRecordZoneWithID(zoneID: CKRecordZoneID, completionHandler: (CKRecordZone?, NSError?) -> Void) public func saveRecordZone(zone: CKRecordZone, completionHandler: (CKRecordZone?, NSError?) -> Void) public func deleteRecordZoneWithID(zoneID: CKRecordZoneID, completionHandler: (CKRecordZoneID?, NSError?) -> Void) /* CKFetchSubscriptionsOperation and CKModifySubscriptionsOperation are the more configurable, CKOperation-based alternative to these methods */ public func fetchSubscriptionWithID(subscriptionID: String, completionHandler: (CKSubscription?, NSError?) -> Void) public func fetchAllSubscriptionsWithCompletionHandler(completionHandler: ([CKSubscription]?, NSError?) -> Void) public func saveSubscription(subscription: CKSubscription, completionHandler: (CKSubscription?, NSError?) -> Void) public func deleteSubscriptionWithID(subscriptionID: String, completionHandler: (String?, NSError?) -> Void) }
Convenience API
![Page 46: The Developer Conference - CloudKit, entendendo a Cloud da Apple](https://reader031.vdocuments.site/reader031/viewer/2022030402/587b235c1a28ab736c8b70f9/html5/thumbnails/46.jpg)
let session = CKRecord(recordType: "Session") session["name"] = "Endentendo a Cloudkit da Apple" session["author"] = "Rodrigo Leite" session["start_date"] = NSDate()
let publicDatabase = CKContainer.defaultContainer().publicCloudDatabase publicDatabase.saveRecord(session) { (record: CKRecord?, error: NSError?) in if (error != nil){ /* Error handling */ }else{ } }
Save ObjectConvenience API
![Page 47: The Developer Conference - CloudKit, entendendo a Cloud da Apple](https://reader031.vdocuments.site/reader031/viewer/2022030402/587b235c1a28ab736c8b70f9/html5/thumbnails/47.jpg)
Fetch ObjectConvenience API
let database = CKContainer.defaultContainer().publicCloudDatabase database.fetchRecordWithID(recordID) { (record, error) in if error != nil { /* *** ERROR HANDLING **** */ }else{ } }
![Page 48: The Developer Conference - CloudKit, entendendo a Cloud da Apple](https://reader031.vdocuments.site/reader031/viewer/2022030402/587b235c1a28ab736c8b70f9/html5/thumbnails/48.jpg)
CKOperation
![Page 49: The Developer Conference - CloudKit, entendendo a Cloud da Apple](https://reader031.vdocuments.site/reader031/viewer/2022030402/587b235c1a28ab736c8b70f9/html5/thumbnails/49.jpg)
Basic NSOperation
public class NSOperation : NSObject { /* **** LIFE CYCLE **** */ public var completionBlock: (() -> Void)? public func cancel() /* ***** STATE ***** */ public var executing: Bool { get } public var finished: Bool { get } /* ***** DEPENDENCIES **** */ public func addDependency(op: NSOperation) public func removeDependency(op: NSOperation) }
![Page 50: The Developer Conference - CloudKit, entendendo a Cloud da Apple](https://reader031.vdocuments.site/reader031/viewer/2022030402/587b235c1a28ab736c8b70f9/html5/thumbnails/50.jpg)
Basic NSOperationQueue
public class NSOperationQueue : NSObject { /* ******* START OPERATION **** */ public func addOperations(ops: [NSOperation], waitUntilFinished wait: Bool) public var operations: [NSOperation] { get } /* ****** CANCEL OPERATION **** */ public var suspended: Bool public func cancelAllOperations() }
![Page 51: The Developer Conference - CloudKit, entendendo a Cloud da Apple](https://reader031.vdocuments.site/reader031/viewer/2022030402/587b235c1a28ab736c8b70f9/html5/thumbnails/51.jpg)
CKOperationpublic class CKFetchRecordsOperation : CKDatabaseOperation { public init() public convenience init(recordIDs: [CKRecordID]) public class func fetchCurrentUserRecordOperation() -> Self public var recordIDs: [CKRecordID]? /* Declares which user-defined keys should be fetched and added to the resulting CKRecords. If nil, declares the entire record should be downloaded. If set to an empty array, declares that no user fields should be downloaded. Defaults to nil. */ public var desiredKeys: [String]? /* Called repeatedly during transfer. */ public var perRecordProgressBlock: ((CKRecordID, Double) -> Void)? /* Called on success or failure for each record. */ public var perRecordCompletionBlock: ((CKRecord?, CKRecordID?, NSError?) -> Void)? /* This block is called when the operation completes. The [NSOperation completionBlock] will also be called if both are set. If the error is CKErrorPartialFailure, the error's userInfo dictionary contains a dictionary of recordIDs to errors keyed off of CKPartialErrorsByItemIDKey. */ public var fetchRecordsCompletionBlock: (([CKRecordID : CKRecord]?, NSError?) -> Void)? }
![Page 52: The Developer Conference - CloudKit, entendendo a Cloud da Apple](https://reader031.vdocuments.site/reader031/viewer/2022030402/587b235c1a28ab736c8b70f9/html5/thumbnails/52.jpg)
let database = CKContainer.defaultContainer().publicCloudDatabase database.fetchRecordWithID(recordID) { (record, error) in ... database.fetchRecordWithID(otherRecordID, completionHandler: { (record, error) in ...
database.saveRecord(otherRecord, completionHandler: { (record, error) in .... }) }) }
Convenience API
![Page 53: The Developer Conference - CloudKit, entendendo a Cloud da Apple](https://reader031.vdocuments.site/reader031/viewer/2022030402/587b235c1a28ab736c8b70f9/html5/thumbnails/53.jpg)
var session : CKRecord? var attendees = [CKRecord]() let firstQuery = CKQuery(recordType: "Session", predicate: NSPredicate(format: "name == %@", "Cloudkit")) let firstFetch = CKQueryOperation(query: firstQuery) firstFetch.recordFetchedBlock = { record in session = record } let reference = CKReference(record: session!, action: .None ) let secondQuery = CKQuery(recordType: "Atendee", predicate: NSPredicate(format: "reference == %@", reference)) let secondFetch = CKQueryOperation(query: secondQuery) secondFetch.recordFetchedBlock = { record in attendees.append(record) } secondFetch.addDependency(firstFetch) let queue = NSOperationQueue() queue.addOperations([firstFetch, secondFetch], waitUntilFinished: false)
Dependent Task• Fetch all attendee in a session
![Page 54: The Developer Conference - CloudKit, entendendo a Cloud da Apple](https://reader031.vdocuments.site/reader031/viewer/2022030402/587b235c1a28ab736c8b70f9/html5/thumbnails/54.jpg)
CKQuery
![Page 55: The Developer Conference - CloudKit, entendendo a Cloud da Apple](https://reader031.vdocuments.site/reader031/viewer/2022030402/587b235c1a28ab736c8b70f9/html5/thumbnails/55.jpg)
NSPredicateCKQuery
CKQuery only accepts a subset of predicate behaviorsRules
• Predicates are based on a format string• Predicates operate only on fields containing primitive data forms
![Page 56: The Developer Conference - CloudKit, entendendo a Cloud da Apple](https://reader031.vdocuments.site/reader031/viewer/2022030402/587b235c1a28ab736c8b70f9/html5/thumbnails/56.jpg)
NSPredicateCKQuery
![Page 57: The Developer Conference - CloudKit, entendendo a Cloud da Apple](https://reader031.vdocuments.site/reader031/viewer/2022030402/587b235c1a28ab736c8b70f9/html5/thumbnails/57.jpg)
PaginationCKQueryOperation
class KBQueryOperation<T:KBRecord>{ var objects: [CKRecord]? var query: CKQuery? var cursor: CKQueryCursor? var limit: Int? var operation: CKQueryOperation? func performQuery(completion: (result:[T]?, error: NSError?) -> Void){ self.operation = cursor == nil ? CKQueryOperation(query: self.query!) : CKQueryOperation(cursor: cursor!) if let resultLimit = limit{ self.operation!.resultsLimit = resultLimit } self.operation!.recordFetchedBlock = { (record: CKRecord) -> Void in self.objects?.append(record) } self.operation!.queryCompletionBlock = { (cursor: CKQueryCursor?, error: NSError?) -> Void in if error != nil{ completion(result: nil, error: error) return } self.cursor = cursor let values = self.objects?.map({ (element) -> T in return T(record: element) }) completion(result: values, error: nil) } KBCloudKit.dataBaseFromContainer(type: .PUBLIC).addOperation(operation!) } func resetQuery(){ self.cursor = nil self.objects = [CKRecord]() } }
![Page 58: The Developer Conference - CloudKit, entendendo a Cloud da Apple](https://reader031.vdocuments.site/reader031/viewer/2022030402/587b235c1a28ab736c8b70f9/html5/thumbnails/58.jpg)
https://gitlab.com/rodrigo_leite/TDConf.git