Handoff is part of Apple's Continuity system. It allows users to begin a task or activity on one device, then continue it on another one. It's actually extremely simple to implement, all you do is tell the system what the user is currently doing in your app, and the system handles the rest. Here it is in code:
Now, if the user picks up another device the activity your app's icon will appear in the bottom left of the user's lock screen on iOS, or in the dock on OS X, and the user can continue where they left off. To wrap things up, we just need to implement two additional UIApplicationDelegate methods:
funcapplication(application:UIApplication,willContinueUserActivityWithTypeuserActivityType:String)->Bool{returntrue}funcapplication(application:UIApplication,continueUserActivityuserActivity:NSUserActivity,restorationHandler:([AnyObject]?)->Void)->Bool{// use the userActivity object to restore the state// needed for the user to continue what they were doingreturntrue}
We continue our tour through CloudKit today with a look at CKDiscoveredUserInfo and it's associated functions. CKDiscoveredUserInfo actually pop up in two different use cases: Grabbing the user's first and last name as well as letting them discover their friends who are also using your app. Let's get started, first we request permission:
Then we fetch the current user's CKRecord, and fetch their name:
container.fetchUserRecordIDWithCompletionHandler{(recordID,error)inguarderror==nilelse{return}guardletrecordID=recordIDelse{return}container.discoverUserInfoWithUserRecordID(recordID){(info,fetchError)in// use info.firstName and info.lastName however you need}}
All that's left is to let the user discover their friends:
container.discoverAllContactUserInfosWithCompletionHandler{(users,error)inguarderror==nilelse{return}guardletusers=usersas[CKDiscoveredUserInfo]else{return}foruserinusers{// use user.userRecordID to make// whatever connections you need}}
CloudKit lives on the client. You write Swift or Objective-C code to interact with Apple's iCloud servers to save and retrieve data. But what if your app wants to support push notifications? Don’t worry CloudKit has you covered. Use CKSubscription to tell CloudKit you'd like to know when records matching a predicate are created, updated, or deleted. CloudKit will deliver a special push notification to your app denoting the change, which you can customize for your needs.
Let's take a look at setting it up: (don't forget to setup and register for push notifications!)
letpublicDB=CKContainer.defaultContainer().publicCloudDatabaseletsubscription=CKSubscription(recordType:"Spaceships",predicate:NSPredicate(format:"TRUEPREDICATE"),options:.FiresOnRecordCreation)letinfo=CKNotificationInfo()info.alertBody="New Spaceship Entered the Fleet!"info.shouldBadge=truesubscription.notificationInfo=infopublicDB.saveSubscription(subscription){record,errorin}
Then when you receive the push notification use it's userInfo to create a CKNotification object and grab the ID of the new record:
letnotification:CKNotification=CKNotification(fromRemoteNotificationDictionary:userInfo)ifnotification.notificationType==CKNotificationType.Query{letqueryNotif=notificationas!CKQueryNotification// do something interesting with queryNotif.recordID}
CloudKit is Apple's API for storing and retrieving data from iCloud. With the recent introduction of the CloudKit Web Services API as well as CloudKit JS, CloudKit is now a very attracive option for the backend of your next app.
Let's take a look at the very basics of using CloudKit to create, retrieve, update and delete records:
Creating a Record
letpublicDB=CKContainer.defaultContainer().publicCloudDatabaseletspaceshipRecord=CKRecord(recordType:"Spaceship")spaceshipRecord["model"]="T-16"spaceshipRecord["maxSpeed"]=1200// in kmpublicDB.saveRecord(spaceshipRecord){(record,error)in}
One of the coolest new features in iOS 9 is the new Picture in Picture functionality on iPad. This lets users watch video content from an app even while it's in the background.
To support it in our app, we'll first make sure you set the Playback audio category in our application(application:didFinishLaunchingWithOptions:) function:
Then we'll use AVPlayerViewController to play video content. Picture in Picture mode will automatically kick-in if our app enters background but only if: 1.) our player is full screen, 2.) video content is playing in it, and 3.) Picture in Picture is supported on the device.
Next we'll implement this wonderfully long delegate method to restore our player UI when the user returns from Picture in Picture mode:
Interacting with a user's Contacts database used to be, shall we say, "less than ideal". The AddressBook framework was great for it’s time, but it’s a bit past it's prime these days.
Contacts and Contacts UI are two new frameworks in iOS 9 (and OS X + watchOS) that make integrating Contact data into your app a breeze.
Here's how easy it is to search a user’s contacts and present one for viewing:
Core Spotlight allows your content to appear in the results of system-level Spotlight searches.
letattrSet=CSSearchableItemAttributeSet(itemContentType:kUTTypeTextasString)attrSet.title="#23: CoreSpotlight"attrSet.contentDescription="CoreSpotlight allows your content to appear in the results of system-level Spotlight searches."letitem=CSSearchableItem(uniqueIdentifier:"023",domainIdentifier:"com.lilbitesofcocoa.bites",attributeSet:attrSet)CSSearchableIndex.defaultSearchableIndex().indexSearchableItems([item]){errorinprint("Success!")}
Of course Core Spotlight is just one of many ways to get your content into search results, be sure to also look into the NSUserActivity APIs as well as Apple's Web markup guides.
letsomething=Product()switchsomething{caseisProduct:print("Found a product")caseletpersonasPerson:print("Found a person: \(person.name)")default:print("Found an unknown thing.")}
Where
letcontentOffset=(0,30.0)switchcontentOffset{caselet(_,y)wherey<0:print("Scrolled up")caselet(_,y)where(0...60)~=y:print("scrolling top area")default:println("just scrolling")}
Swift 2
New in Swift 2, you can now use any Swift pattern as the clause of an if statement:
letcomments=7ifcase1...10=commentCount{print("some comments")}elseifcase11..100=commentCount{print("lots of comments")}
And in Swift 2's new error handling:
do{trysend(message:"Hello")}catchSendError.Offline{print("user is offline")}catchSendError.RateLimited{print("stop spamming")}catchSendError.Blocked(letreason){print("user was blocked because \(reason)")}
CLKTextProvider is part of ClockKit in watchOS 2. It's an abstract base class of a family of classes that allow you to provide text content for a complication on Apple Watch. Visual space on the Apple Watch's screen is so constrained, that Apple has created a whole suite of classes for gracefully degrading the way values are displayed in complications, depending on how much space is available.
Essentially, you tell the class the value you want displayed, and the system handles formatting and best fitting the content for the constraints of the complication it's included in.
importClockKitletnow=NSDate()letunits:NSCalendarUnit=[.Weekday,.Month,.Day]lettextProvider=CLKDateTextProvider(now,units)// textProvider will now render one// of these strings, depending on// the environment its in:// "Monday, June 22"// "Mon, Jun 22"// "Jun 22"// "22"
In addition, ClockKit also contains text providers for many common values you might want to include in a complication such as:
Dates/times like "Monday June 22" or "10:09"
Relative dates/times including 3 different styles: Natural ("2HRS 11MINS") , Timer ("09:42"), and Offset ("+31 MINUTES")
Time intervals like "1:00-2:30PM"
There's also a generic ‘simple' text provider for gracefully degrading your own custom text content.
CLKTextProvider (as well as the rest of ClockKit) is sadly only available in watchOS at the moment. It's such a great little set of utilities, here's hoping it makes it way into iOS and OS X at some point!