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.
Validating data is usually one of the "chores" we encounter while building apps. It can be annoying and boring code to write, and can be a huge source of bugs. Today we'll check out a great library called FormValidatorSwift that can help us avoid all these issues. Let's take a look.
The core of FormValidatorSwift is built around checking if a String passes some sort of test to be deemed 'valid'.
We'll use individual Conditions or combined sets of Conditions called Validators. We'll attach these to controls like Text Fields and Text Views to allow them to be validated.
Let's try out the included ValidatorTextField to validate an email address:
Then, we'll configure it to allow the user to begin entering an email address that's invalid like "hello@", and specify that it should only be validated when it loses focus.
Xcode Source Editor Extensions are really starting to come into their own. Today we'll look at one that solves an age-old annoyance for Xcode users: Importing.
We've all been there. We're deep down in the depths of file, and we realize we need to import a module. We dutifully scroll all the way up, type the import, then scroll back down trying to find our place, and get back in "the zone". Yuck.
As the name suggests, it allows us to type an import Module statement anywhere, then press a keyboard shortcut and have the import fly to the top where it belongs.
Attributed Strings are a fantastic way to work with rich, styled-text. (We've covered them in Bites #143 & #144 for the curious.) We've even looked at ways to improve upon how verbose the FoundationNSAttributedString API can be.
Today we'll check out another approach using a library from Eddie Kaiger called SwiftyAttributes. It dramatically improves how we work with Attributed Strings. Let's dive in.
Let's start by looking at how things work in vanilla Foundation:
Things get even nicer when we need to concatenate two NSAttributedStrings together. We've all had to do this before and it could have involved applying attributes to specific ranges, etc. Now, we can use a much more declarative and readable syntax:
letsomeString="We can easily ".withFont(.systemFont(ofSize:16))+"underline".withFont(.systemFont(ofSize:16)).withUnderlineStyle(.styleSingle)+" certain words.".withFont(.systemFont(ofSize:16))
Under the hood, SwiftyAttributes takes a pragmatic approach by extending both Swift's String type as well as NSAttributedString with a fairly comprehensive set of delicious, sugary functions:
UITableView & UICollectionView have some fantastic animation capabilities. We can animate items and sections being inserted, removed, moved, etc. We've all been there though, reloadData is sitting right there, and is conceptually so simple. Wouldn't it be great if we could enable those fancy animations in our views, with the conceptually simplicity of reloadData?
Today we'll check out Dwifft, a library from Jack Flintermann that can help us achieve this. Let's dive in.
We'll begin with a regular UITableViewController. (Dwifft works just as well on UICollectionViews).
First we'll need a TableViewDiffCalculator. This is a generic type, so we'll tell it that we're going to be display a bunch of Strings.
Next we'll initialize our data with some random items (just a randomly ordered array of Strings). We'll also use a property observer to let our diff calculator know whenever our items change.
Alerts have been around since iOS was iPhone OS. First in the form of UIAlertView, and now through UIAlertController (Bite #44). The built-in system alerts work great, but sometimes we want something fancier 🎩. Today we'll check out PMAlertController from Paolo Musolino, a library that allows us to easily display great looking alerts in our app. Let's take a look.
PMAlertController is essentially a fancier replacement for the styles that UIKit'sUIAlertController already provides.
The "Alert" Style is 270 points wide (matching the system's alerts):
The "Walkthrough" Style is almost the full width of the screen and is appropriate for more in-depth alerts/dialogs (such as those for explaining why our app is requesting permission for some of the user's data):
We're given a title, description and image to work with:
letalertVC=PMAlertController(title:"Locate your device",description:"Enables access to your...",image:UIImage(named:"flag.png"),style:.alert)alertVC.addAction(PMAlertAction(title:"Cancel",style:.cancel,action:{in}))alertVC.addAction(PMAlertAction(title:"Allow",style:.default,action:{in}))present(alertVC,animated:true,completion:nil)
We instantiate the view controller, add some actions (each with their own closure handler that will be called when the action is tapped), and present it.
Neat!
Libraries like PMAlertController can help us easily add some polish to our apps, but they can also be a great way to learn about creating custom controls in general.
We've looked at protocols in Swift in Bite #232, but we haven't really seen a ton of "real world" examples. Today we'll check out a library called CostumeKit. It's a set of base protocols that can assist us in visually styling or "themeing" our apps. Along the way we'll use some protocols "for real". Let's jump in.
Author's Note: Full disclosure, CostumeKit is written by me. I'm a huge fan of conventions, also it's a nice basic example of Protocols. I use it in all my apps.
To try this out, we'll be working on an imaginary Little Bites of Cocoaapp.
We're almost there, next we need to create the actual Costume our app will wear. For this we'll implement one more protocol. This protocol has no requirements. It serves as more of a convention really.
For good measure, we'll define a night-mode costume as well:
openclassLittleBitesNightCostume:LittleBitesCostume{publicoverridefunccontentTextColor()->Color{returnColor.white}overridepublicvarname:String{return"Night Mode"}overridepublicvardescription:String{return"For reading in the dark."}}
That's where CostumeKit stops. We get a super-tiny bit of functionality "for free" (fonts, color parsing), but the idea is that we're merely following a set of conventions to help guide us through writing this code.
Let's finish up by looking at how we might actually use costumes in our app. Everything from this point on would live inside our app's code (and isn't part of CostumeKit).
We'll make a Wardrobe type and static instance to manage all our costumes:
importCostumeKitpublicclassWardrobe{private(set)varcurrent:LittleBitesCostumeinit(initialCostume:LittleBitesCostume){current=initialCostume}publicfuncchange(costume:LittleBitesCostume,animated:Bool=true){// TODO: In the future, we'll animate this change using UIView transitions and RxSwift.current=costume}}publicletwardrobe=Wardrobe(initialCostume:LittleBitesCostume())publicvarcostume:LittleBitesCostume{returnwardrobe.current}
Now in our regular UIKit code, we can use our current costume:
Xcode Project folders can be a messy place. Today we'll check out a tool from the folks at Venmo that can help us tidy up called Synx. Let's take a look.
At its core, Synx's main purpose is to reorganize the files and folders in our Xcode project folder to match the groups and structure we've setup inside Xcode's Navigator pane.
We can start by organizing a project full of content:
Then we can simply head into our project's directory and run the main command:
synx ./OCMock.xcodeproj
Synx will work its magic and re-organize our files on disk, creating directories and moving files as needed to make things match the groups in our project.
Additionally, we can also use Synx to remove files no longer referenced in our project, like this:
synx --prune ./OCMock.xcodeproj
We're also provided a couple arguments to help us control how Synx behaves.
We can exclude files:
synx --exclusion /OCMockTests ./OCMock.xcodeproj
Last but not least, for those of us who like to manually sort our files by concept rather than name, we can disable sorting:
synx --no-sort-by-name ./OCMock.xcodeproj
Choosing how to organize projects can be a very subjective and personal choice, this is just one approach. Always use whatever works best.
Testing network requests can be tricky. Generating mock data, handling HTTP routes, etc. Thing get complicated quickly. Today we'll check out a library from devlucky called Kakapo that can help us tame all this. Let's get started.
One of the best features of Kakapo is how easy it is start using. We can create a new Router for a domain, and start adding intercepted routes like this:
In the above example, we're returning static data. Let's kick things up a notch and return some dynamic data. This is another place Kakapo really shines: