Like in Bite #99, we'll use Auto Layout Visual Format Language to pin the stack view's edges to its superview. Look at that, not bad for our first try!
Those views are close talkers, let's add some spacing:
stackView.spacing=10.0
Ack! What the heck is going on here?!
Let's break it down: In the default โFill' distribution mode, if views don't naturally fill the axis of the stack view, the stack view will resize one (or more) according to their hugging priority (covered in Bite #69).
We'll solve our issue by setting a low hugging priority on our label, signaling to the stack view that it be the one to stretch, not our image view.
Shared Links Extensions arrived with iOS 9 and OS X El Capitan this year. They allow our app to insert content into the users' Shared Links section of Safari on iOS or OS X. Let's add one to our fictional Little Bites of Cocoaapp so users can see all the latest Bites right inside Shared Links.
We'll start by going to File > New > Target... in Xcode and choosing a Shared Links Extension.
This will provide us with a new group in our project with one file inside, called RequestHandler.swift.
In this file there's one function called beginRequestWithExtensionContext(context:).
iOS will call this on our extension and that will be our cue to run whatever code we need to load the content we'd like to show in Shared Links, then return it in the form of an array of NSExtensionItems.
We'll return them via a completion function on the context we're passed in.
Universal Links arrived with iOS 9. Conceptually they're a way for us to logically tie the content in our app to the content on our website. Once this is done, iOS will be able to launch our app when a user taps a link somewhere, rather than opening our site in Safari. Let's take a further look by adding Universal Links to a fictional Little Bites of Cocoaapp. We'll start by registering and setting up SSL for our domain: littlebitesofcocoa.com.
Then, we'll head into Xcode and to the Capabilities tab of our project. We'll flip on the switch for Associated Domains, then click the + button and add our domain. Note that we prefix it with the phrase applinks:.
Now, our app will silently make an HTTP GET request to https://littlebitesofcocoa.com/apple-app-site-association.
It will expect us to return some JSON which describes our app's Bundle ID, and which paths should open it.
We'll open all paths on our domain using a wildcard character here, but we could easily, for example, limit to just Bite URLs.
After creating the file, we'll need to sign it so it is returned with a Content-Type of application/pkcs7-mime on our server. We'll use a command like the one shown here to sign the file. (This part stinks, but there's no way around it).
Lastly, we'll wire up the other side of the equation. When a user opens a Universal Link that iOS recognizes, it will call the same delegate function that's used to implement features like Handoff (Bite #29) and Spotlight Search (Bite #23). We'll check if it's a Universal Links activity type, then use JLRoutes (Bite #62) to open a section of our app.
Testing is incredibly important in ensuring our app arrives to our users in as good a state as possible.
Xcode has had great unit testing support for a few releases now, but testing our UI has always been a challenge.
Instruments added support for it a while back, but itโs never felt like a first class citizen... Until now!
Xcode 7 brings us an awesome, fully baked set of UI testing tools. We can even make Xcode write much of your test code for us by simply interacting with our app.
Here's an example test created using the default Master-Detail template in Xcode. It presses the add button 3 times, then verifies that 3 cells now exist in the table view:
Recording UI Tests couldn't be easier. We just write an new empty test function, put our cursor in the middle of it, and press record.
UI Testing uses Accessibility under the hood to identify and retrieve UI elements at runtime. Just one more reason to make our apps as accessible as possible!
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.
SFSafariViewController is another new addition in iOS 9, and itโs a great one.
Get ready to throw out all that custom in-app browser or third-party library code youโve been using.
Unlike other solutions, SFSafariViewController embeds all of the power of Safari on iOS (including Autofill, shared cookies, etc.) directly into your app.
Replacing your existing solutions should be trivial for most people, hereโs how:
iOS has had support for hardware keyboard shortcuts for a while now. New in iOS 9, Apple has made some great improvements to how apps can take advantage of them. Your app can now register keyboard shortcuts per view controller, and all currently valid shortcuts will be neatly
summarized when the user brings up the new keyboard shortcuts view.
Wiring up a new keyboard shortcut in this system couldn't be easier. Just define a new function, create a new UIKeyCommand and then call addKeyCommand on your view controller:
// inside some UIViewController subclass:overridefuncviewDidLoad(){super.viewDidLoad()letshortcut=UIKeyCommand(input:"n",modifierFlags:UIKeyModifierFlags.Command,action:"createNewFile:")addKeyCommand(shortcut)}funccreateNewFile(command:UIKeyCommand){// do the thing}