the developer conference - cloudkit, entendendo a cloud da apple

59
Globalcode – Open4education Trilha – iOS Rodrigo Freitas Leite iOS Developer

Upload: rodrigo-leite

Post on 23-Jan-2018

367 views

Category:

Mobile


0 download

TRANSCRIPT

Page 1: The Developer Conference - CloudKit, entendendo a Cloud da Apple

Globalcode – Open4education

Trilha – iOSRodrigo Freitas Leite

iOS Developer

Page 2: The Developer Conference - CloudKit, entendendo a Cloud da Apple

CloudKitEntendendo a cloud da Apple

Page 4: The Developer Conference - CloudKit, entendendo a Cloud da Apple

www.kobe.io

Focus on mobile development

OutsourcingProduct Development

Page 5: The Developer Conference - CloudKit, entendendo a Cloud da Apple

www.kobe.io

Page 6: The Developer Conference - CloudKit, entendendo a Cloud da Apple

What is Cloudkit ?

Page 7: The Developer Conference - CloudKit, entendendo a Cloud da Apple
Page 8: The Developer Conference - CloudKit, entendendo a Cloud da Apple

How do we start an app with CloudKit?

Page 9: The Developer Conference - CloudKit, entendendo a Cloud da Apple

Register iCloud Container

Page 10: The Developer Conference - CloudKit, entendendo a Cloud da Apple
Page 11: The Developer Conference - CloudKit, entendendo a Cloud da Apple

Enable CloudKit Capability

Page 12: The Developer Conference - CloudKit, entendendo a Cloud da Apple
Page 13: The Developer Conference - CloudKit, entendendo a Cloud da Apple

CloudKit Dashboard

Page 14: The Developer Conference - CloudKit, entendendo a Cloud da Apple
Page 15: The Developer Conference - CloudKit, entendendo a Cloud da Apple
Page 16: The Developer Conference - CloudKit, entendendo a Cloud da Apple

Record Type

Page 17: The Developer Conference - CloudKit, entendendo a Cloud da Apple

Security Roles

Page 18: The Developer Conference - CloudKit, entendendo a Cloud da Apple

Subscription Types

Page 19: The Developer Conference - CloudKit, entendendo a Cloud da Apple

User Records

Page 20: The Developer Conference - CloudKit, entendendo a Cloud da Apple

Public Default Zone

Page 21: The Developer Conference - CloudKit, entendendo a Cloud da Apple

Usage

Page 22: The Developer Conference - CloudKit, entendendo a Cloud da Apple

Team

Page 23: The Developer Conference - CloudKit, entendendo a Cloud da Apple

Deployment

Page 24: The Developer Conference - CloudKit, entendendo a Cloud da Apple

CloudKit Objects

Page 25: The Developer Conference - CloudKit, entendendo a Cloud da Apple

Container

CKContainerOne container per application - usual

CKContainer(identifier: containerName)CKContainer.defaultContainer()

ApplicationContainer

CloudKit

Page 26: The Developer Conference - CloudKit, entendendo a Cloud da Apple

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

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

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

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

Record

Public

Record Record Record

Record Record Record

Page 31: The Developer Conference - CloudKit, entendendo a Cloud da Apple

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

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

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

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

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

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

References

Public

SessionAttendee

Session

Attendee

Attendee

Page 38: The Developer Conference - CloudKit, entendendo a Cloud da Apple

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

Assets

Public

Record

Record

Asset

Page 40: The Developer Conference - CloudKit, entendendo a Cloud da Apple

Assets

Record

Record

Public Bulk Storage

Asset

Page 41: The Developer Conference - CloudKit, entendendo a Cloud da Apple

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

Login

Page 43: The Developer Conference - CloudKit, entendendo a Cloud da Apple

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

Convenience API

Page 45: The Developer Conference - CloudKit, entendendo a Cloud da Apple

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

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

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

CKOperation

Page 49: The Developer Conference - CloudKit, entendendo a Cloud da Apple

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

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

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

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

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

CKQuery

Page 55: The Developer Conference - CloudKit, entendendo a Cloud da Apple

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

NSPredicateCKQuery

Page 57: The Developer Conference - CloudKit, entendendo a Cloud da Apple

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://gitlab.com/rodrigo_leite/TDConf.git

Page 59: The Developer Conference - CloudKit, entendendo a Cloud da Apple

CloudKitEntendendo a cloud da Apple

[email protected]