In Bite #286, we looked at the basics of using DateFormatters to transform Dates into Strings.
Today we'll explore another common use case of Dates in our apps: "relative" date strings.
Think "2 days ago", "10 minutes ago", "Yesterday", and "Just now". Representing timestamps this way has become common, and it can help our users more quickly understand how old a piece of content is.
Let's add this functionality to our app by extending Date to give it a new computed property to do this.
We'll begin by adding a new File to our Xcode Project. We'll call it Date+Relative.swift. (The Type+SomeExtensionName convention is borrowed from Objective-C.
Nice. Next, we'll need a way to calculate how much time is in between now, and self (from the extended Date's point of view). We could do a bunch of ugly math, but we've got a better way!
This is a fantastic use case for Foundation's DateComponents type. It has a function that can calculate the difference between two Dates, and provide it to us in neatly (pre-calculated) components like days, months, hours, seconds, etc.
We ask the current Calendar to please calculate the quantity of each of the components we passed in for the time between the Date we passed in as the from argument to the Date we passed into the to argument.
Beautiful. Now, the returned DateComponents type has a bunch of properties we'll use to build our relatively formatted date `String.
Finally, we'll inspect each date component (starting with most broad at the top) and return a nicely formatted String:
Doing things manually like this allows us to completely customize and control exactly how this relative date strings appear in our app.
This is fairly straightforward. We get a little fancy for the "days" component, allowing for "yesterday". We could also easily add support for future dates (i.e. "tomorrow") here as well.
All that's left to do is test it out. We can do that easily by constructing some Dates in the past, then printing our new property:
Formatting dates and times is one of those common tasks we all have to do in almost every app. Today we'll take a look at how to use Foundation's solution for this: DateFormatter.
DateFormatters are incredibly powerful. Their core purpose is transforming Dates into Strings and Strings into Dates. They handle things like localization for us under the hood. Let's try one out.
We'll create a new formatter:
letformatter=DateFormatter()
Then we'll need to set a "format" on it. This is a string of characters that represent the date we're going to try to parse or render. Often these appear as one or more repeated series of letters like:
formatter.dateFormat="MMM yyyy"
To see a rendered date string using this format, we can ask for one like this:
formatter.string(from:Date())// "Jan 2017"
We can play around with the format for different results:
The first is that DateFormatters have historically been heavy-weight objects to create. Performance has definitely improved over the years, but if we can, it's probably a good idea to keep one around instead of creating on the fly each time we need it. (For example we wouldn't want to be creating a new DateFormatter inside a UITableView or UICollectionView"cell for row" style delegate function).
The second is that these format strings are opaque and hard to understand at a glance. To solve this, friend of the show (and creator of the awesome NSScreencasts) Ben Scheirman has created a site called nsdateformatter.com.
There we can not only find easy, glance-able examples and references for all the different date format tokens, but we can also test out formats right there in the browser! Super handy.
We've only scratched the surface of what Foundation is capable of when it comes to Dates. Tune in tomorrow to learn more.
We've got one of our favorite sponsors back this week, it's buddybuild! Long time readers will remember that buddybuild is a fantastic mobile continuous integration, delivery, crash reporting and feedback platform, all in one.
It takes just minutes to set up, let's check it out!
We'll head over to buddybuild.com and click Get Started. We'll sign up with Github (we could also use Bitbucket, GitLab, or sign up with email / password to for repos on any other git server). Neat!
Next, buddybuild will let us choose a git repo to create our first project with.
Once we select the repo we want to build, buddybuild will get to work building our app for the first time. After that build is complete, our app is set up on buddybuild - it's that easy.
Now, we'll be able to trigger a new build (and run our tests with code coverage) at any time with a simple git push!
After that build is complete, our app is set up on buddybuild - it's that easy.
With buddybuild, we won't need to wait for App Store processing time or reviews before deploying to testers.
Speaking of deployment, buddybuild's email (and Slack!) based deployment service can deploy instantly on every build, every night, or at the push of a button.
Buddybuild's deployment service also handles the process of adding new users (and their devices) by automatically managing UDIDs, iOS provisioning profiles and signing identities. (Fantastic UX for both testers and devs!)
Only buddybuild goes even farther, and gives us a fully integrated feedback platform. Once users have installed our app and are testing it out, they can send their feedback (along with important diagnostic details) by simply taking a screenshot.
If our app ever crashes, buddybuild's will trace back and highlight the exact line of offending source code that caused the crash, telling us which users were affected, and how many times the crash happened.
Each crash is also recorded with an Instant Replay - to show you exactly what your users were doing in the moments leading up to the crash. Awesome!
Buddybuild is also a great community citizen, and has our backs as iOS developers. For example, they'll give us a heads up on any potential breaking changes in Xcode. Within 48 hours of any Xcode release (including betas!), buddybuild will automatically takes our most recent successful build, and build and run tests against it using the latest version of Xcode. Then it will email us the results. How cool is that?!
Last but certainly not least, buddybuild comes with built-in integrations with tons of services we all know and love such as GitHub, BitBucket, GitLab, Slack, JIRA Pivotal Tracker, Slack, HipChat and more!
Whether we need sample values while prototyping our app's interface, or some multipliers for our game's logic, random data can be incredibly useful when programming. Today we'll check out a great library from Nikolai Vazquez called RandomKit that makes generating random data both simple and intuitive. Let's begin.
RandomKit is built on a set of Swift Protocols. We're provided Random, RandomWithinRange, RandomToValue, and many more. RandomKit then extends a bunch of types to conform to these protocols.
(This is great because it means we can easily add RandomKit-style functionality to our own types, if we ever need to. Neat.)
Let's try out the basics. Some of the most common things to generate randomly are numbers and booleans. RandomKit has us well covered here, supporting all the major numerical Foundation types (and more):
Last but not least, we can even grab random values for CoreGraphics types:
CGPoint.random(within:0...50,0...50)// {x 23.284 y 45.302 }CGSize.random(within:0...50,0...50)// {w 29.475 h 12.863 }CGRect.random()// {x 3.872 y 46.15 w 8.852 h 20.201}
These examples were just a (sorry) random-sampling of RandomKit's functionality. It has a ton more to offer.
Today we'll dive back into the world of Xcode Source Editor Extensions (Bite #239). These extensions can not only help us save time and effort, they're also a great way to customize Xcode to our exact needs. Let's dive in! 🏊
First up, Cleaner Closures. We can use CleanClosureXcode from Patrick Balestra to clean up all those unnecessary ('s and )'s from our Swift closure definitions:
Beautiful. No more manually arrow-key-ing around to get rid of those.
Next, let's look at a common feature of many IDEs and text editors: the ability to "jump" the cursor multiple lines up or down. Xcode can't really do that... until now. Thanks to Jump, we're given a few new menu items in our Editor menu to move the cursor up or down by 2 or 5 lines. Neat.
Pro Tip: We can use the Key Bindings tab of Xcode'sPreferences window to customize the keyboard shortcuts for each of these movement commands (or any other commands).
This extension allows us to select some text, and then insert a new function definition into our code, complete with documentation comment, and placeholders we can press tab to jump between.
This allows us to employ a workflow of:
1.) Call a function that doesn't yet exist when writing some code as a sort of "placeholder".
2.) When we're done with that chunk of work, select the name portion of the function call and press a keyboard shortcut to "generate" the function and insert it into our file.
3.) Profit!
We're welcoming back one of our favorite sponsors again this week, it's Zendesk!
None of us have ever built a flawless app.
Chances are, no matter how good we think our app's user experience is, there's probably something users will need help with while they're in our app.
Yet in many apps, getting help is reduced to a "contact us" button that launches an compose email screen, or a just drops the user on a web page.
By forcing folks out of the app to get help, small problems can turn into big annoyances, and those will almost certainly turn into negative App Store reviews and poor ratings.
With Zendesk's Mobile SDKs, we can bring native, in-app support functionality to our apps quickly and easily.
Our users can view help and support content, and even submit tickets to support without ever leaving our app. Neat!
Tickets go into Zendesk and can include technical details about the user and their device, history with our apps, and more.
Best of all, it's included with Zendesk at no extra charge.
We can use Zendesk's "out-of-the-box" iOS UI components to get up and running quickly, or we can build your own UI with SDK API Providers.
Integrating our apps with HTTP APIs often involves a fair amount of "busy work". Writing models to match API responses, manually iterating each field in a JSON object, and typing each in as a Swift property can be a bummer. Today we'll check out a great new tool from Josh Smith called json2swift that can help us here. It can generate Swift model code from a JSON object. Let's give it a try.
After we've installed json2swift, we can run it like this:
json2swift Spaceship.json
This will create a new file called Spaceship.swift in the same directory as our .json.
This means if our Spaceship.json file looked like this:
{"name":"Tantive IV","topSpeed":950}
The resulting json2swift-generated Swift model would look like this:
json2swift has generated an immutable Swift struct from our JSON file. Pro Tip: We can also run this on a directory full of JSON files, and it will process all of them.
json2swift will even try to determine which properties should be optional, and which are required. It will then generate the appropriate init code.
We're even provided some special handling for things like Date parsing. If we put a special String like this in our original JSON:
property, as well as generate the appropriate Date format/parsing code needed to make it work. Neat!
We've only scratched the surface, json2swift has great support for intelligenty inferring types for things like numbers, and even URLs. Learn more about json2swift at git.io/json2swift.
Properly responding integrating with the software keyboard is a big part of building a solid iOS app. Traditionally, this would involve observing NSNotificationCenternotifications and some pretty lengthy boilerplate code. Today we'll look at a great little library from Toto Tvalavadze called Typist that can improve all this. Let's check it out.
Typist works by exposing a way for us to easily "opt-in" to certain keyboardevents:
Typist provides this same interface for a bunch of useful events:
Typist.shared.on(event:.willShow){_in/* TODO */}.on(event:.didShow){_in/* TODO */}.on(event:.willHide){_in/* TODO */}.on(event:.didHide){_in/* TODO */}.on(event:.willChangeFrame){_in/* TODO */}.on(event:.didChangeFrame){_in/* TODO */}.start()}
Finally, inside each event closure, we're given a Typist.KeyboardOptions type that contains strongly-typed properties describing the event:
Here we're guard-ing to make sure the keyboard belongs to our app, and returning early if not.
Then, we use the endFrame property to adjust our own views to accomodate the keyboard.
Neat!
Typist's options type also provides startFrame, animationCurve, and animationDurationproperties to help us match our app's animation to the keyboard's.
During yesterday's MacBook Pro event, Apple announced a fantastic new piece of hardware called the Touch Bar. It's a 1085 x 30 point matte-finish Retina screen that sits above the keyboard on the new MacBook Pros. It can dynamically alter its controls and content as we work in each app on the main screen.
Today we'll look at the basics of adding Touch Bar support to a macOS app. Let's dive in.
First some pre-requisites. You'll need the latest version of Xcode (8.1 at publish time), and the latest version of macOS. Even for those running 10.12.1, this updated 10.12.1 build still needs to be installed to be able to test Touch Bars using Xcode.
After we've made sure we've got the latest versions of everything, we can launch Xcode 8.1 and select Window > Show Touch Bar to see a simulated Touch Bar on screen while we're work on our Mac.
It even floats above all other windows to make it feel a tiny bit more realistic. Neat!
Whew! With that out of the way, we can fire up Xcode and create a new macOS app.
We'll make a new WindowController for our app's initial window, and set its class in Interface Builder.
We'll add an extension to WindowController to adopt the NSTouchBarDelegate protocol. We'll also add an @available statement to make sure it's only available on the latest macOS:
We can test out customization by selecting View > Customize Touch Bar... from our app's menu.
(Pro Tip: Hold Option to change the menu item to Customize Control Strip... instead, which allows us to customize the persistent NSTouchBarItems that are always available on the right side of the Touch Bar). Neat!
We're welcoming back one of our favorite sponsors again this week, it's Zendesk!
None of us have ever built a flawless app.
Chances are, no matter how good we think our app's user experience is, there's probably something users will need help with while they're in our app.
Yet in many apps, getting help is reduced to a "contact us" button that launches an compose email screen, or a just drops the user on a web page.
By forcing folks out of the app to get help, small problems can turn into big annoyances, and those will almost certainly turn into negative App Store reviews and poor ratings.
With Zendesk's Mobile SDKs, we can bring native, in-app support functionality to our apps quickly and easily.
Our users can view help and support content, and even submit tickets to support without ever leaving our app. Neat!
Tickets go into Zendesk and can include technical details about the user and their device, history with our apps, and more.
Best of all, it's included with Zendesk at no extra charge.
We can use Zendesk's "out-of-the-box" iOS UI components to get up and running quickly, or we can build your own UI with SDK API Providers.