In Bite #162, we took our first look at RxSwift, and how it can transform how we write code. We learned how Observables can simplify our code, and mentioned creating our own Observables briefly, but today we'll dive a bit deeper. Let's begin:

Creating our own Observables is how we can bring code that wasn't built with reactive principals in mind, into the RxSwift world. It's helpful to think of Observables as merely a slightly different way to organize code we were already writing.

Let's look at a simple asynchronous function call:

let task = loadSpaceships { spaceships, error in
  guard error == nil else { handleError(error); return }
  self.resultsTableView.reloadData()
}

We can actually use this code as a starting point to write a new function that wraps this code and converts it into an Observable.

We'll be responsible for sending values along, reporting any errors, and letting observers know if/when the work is completed.

func spaceships() -> Observable<[Spaceship]> {
  return Observable.create { o in
    let task = loadSpaceships { spaceships, error in
      guard error == nil else { o.onError(error!); return }

      o.onNext(spaceships)
      o.onCompleted()
    }

    return AnonymousDisposable { task.cancel() }
  }
}

We use Observable's create function to get a reference to an observer in a closure. We can use this observer to send along relevant status updates.

Lastly, we return an AnonymousDisposable closure that cancels the NSURLSessionDataTask when we're disposed.

Now this code can live in the RxSwift world as an Observable, be subscribed to, and be used alongside any other Observables:

Observable.zip(crew(), spaceships()) { return ($0, $1) }
  .subscribeNext { print($0) }

One last note: We've been talking about all of this in terms of RxSwift, but other reactive or functional libraries might have different names for their streams of values. Even if we're using something other than RxSwift, the underlying concepts will usually remain largely the same. We can still use the techniques here to lift the code out of the conventional world and into the reactive one, regardless of which library we're using.

Topics

#162: Reacting with RxSwift ⚗

Topics

We first learned about reactive-style programming in Bite #127, with ReactiveCocoa. (Give that Bite a quick look first if you're new to the topic).

Today we'll check out an alternative solution called RxSwift. It just hit 2.0, so now is a great time to take a look. Let's dive in.

Before we begin it's important to note that there are tons of great libraries available for writing this style of code. We can enjoy the benefits of functional and reactive programming with any of them.

RxSwift is another take on reactive/functional programming. Similar to ReactiveCocoa, RxSwift works with streams of values called Observables. We can subscribe to them, transform them, bind user interface elements to them, and create them.

Additionally, RxSwift ships with RxCocoa, a framework that provides extensions for UIKit that bring it into RxSwift's reactive world.

Let's check out some examples.

Binding a UITextField to a UILabel:

shipNameField.rx_text
  .map { "Launching \($0)..." }
  .bindTo(statusLabel.rx_text)

Creating our own Observable:

Observable<String>.create {
  $0.onNext("Howdy! 🐴")
  $0.onCompleted()

  return NopDisposable.instance
}

Transforming each value change of a search field into an API request, then updating our UI when it completes:

searchBar.rx_text
  .flatMapLatest {
    API.getSearchResults($0)
  }
  .subscribeNext { _ in
    self.tableView.reloadData()
  }

RxSwift can transform how we write code in all the layers of our apps. With tight UIKit integration from RxCocoa, we can now forget about delegates, notifications, KVO, etc and instead use one simple interface to think about how data flows through our app.

Learn more about RxSwift at git.io/rxs

Today we'll tackle a common question from those beginning to learn iOS development:

"UICollectionView and UITableView seem to overlap in terms of functionality in many ways. When should I use one or the other?"

The practical answer is actually a common idiom when building software: What's the simplest possible solution?

Let's look at the basics of table and collection views, then we'll circle back and learn how we apply that answer to our question.

UITableViews are all about vertically scrolling lists of content. They expect us to use them to display rows of content inside sections. We get a ton of conventional "iOS-native" feeling functionality for free such as group-style table views that look like iOS's settings app or system-standard accessory views.

In short: UITableViews give us a lot for free, but they expect us to think in their terms.

UICollectionViews are infinitely more customizable than Table Views. We can completely customize a collection view's layout, even animate between layouts.

UICollectionViews don't provide anywhere near as much functionality out of the box, but they offer an incredible amount of power and capability.

In many ways, Collection Views are the more-capable big sister to Table Views. They aren't constrained by "rows" or "accessory views". They are great for simple grids, all the way up to incredibly complex layouts.

Back to our original answer: What's the simplest possible solution?

We can now answer our question by rephrasing it: Given what I'd like to build, will a UITableView or a UICollectionView help me get there faster, with less (or at least simpler) code?

Building a Settings screen or vertical list of social media posts? A UITableView is probably the way to go.

Building a photo gallery, or perhaps a screen that needs to scroll content horizontally? We'll need a UICollectionView for those.

In either case, if we ever start to feel like we're fighting against UIKit, that's a good time to step back and re-evaluate.

Weekly Sponsor: Buddybuild 🤖🛠

A huge continued thanks Buddybuild for sponsoring this week's Bites!

Buddybuild is the simplest and fastest way to automate our iOS continuous integration and continuous deployment workflows (and much, much more). Let's take a look:

Buddybuild ties together and automates: building, testing, deploying and gathering feedback for our apps. Let's try it.

We'll sign in with Github, and Buddybuild will ask us to choose the repository that contains the app we want to use with Buddybuild.

Next, Buddybuild will pull down our code and look for apps and schemes in our repo, and begin to build our app. We don't have to configure anything or write any scripts, Buddybuild takes care of everything automatically. 🤖

Buddybuild will now build and run our tests each time we push to Github, and we still haven't configured a thing by hand, neat!

Let's continue by importing our certificates and profiles. Buddybuild provides a simple way to do this. We just need to copy/paste and run the command they provide, and all the right files will be securely uploaded. 🔒

Next, we can invite testers, and they can register on their devices. We can even connect our iTunes Connect accounts so we never have to manage new devices, UDIDs, profiles or signing identities again. New testers and their devices will be automatically provisioned on our behalf!

Now, we can now instantly deploy to testers on every build, every night, or on demand.

Testers can provide feedback by taking a screenshot. Buddybuild will kick in and show them a slick custom UI for graphically annotating and sending feedback notes. We'll also get reports of any crashes with the exact line they occurred on.

Last but not least, Buddybuild integrates with tons of services like GitHub, BitBucket, GitLab, Slack, JIRA, Pivotal Tracker, Slack, HipChat, and more.

Buddybuild is an incredible tool that's absolutely packed with great features, try it right now with your own apps at buddybuild.com!

It's quite common to need to display short status messages or notifications inside our apps. Today we'll look at a library called Whisper that is absolutely packed with features that make displaying these types of messages both simple and beautiful. Let's dive in.

Whisper provides 3 different types of display styles. All allow for extensive customization including colors, fonts, etc.

First up is "Whispering" a Message:

let message = Message(
  title: "🚨 Imperial Troops Have Entered the Base!",
  color: .redColor()
)

Whisper(message, to: navigationController, action: .Present)
Silent(navigationController, after: 3)

We call the Silent function right after we present the Whisper, this will dismiss the message after 3 seconds.

Next, let's try "Shouting" an Announcement.

This one's great for longer text, and looks great with an image. We can also pass in an closure to run when the user taps the banner.

let announcement = Announcement(
  title: "Han Solo Says:",
  subtitle: "Who's scruffy lookin'?!",
  image: UIImage(named: "avatar")
)

Shout(announcement, to: self)

Lastly, we can "Whistle" a Murmur to display a subtle, classy message in the status bar:

let murmur = Murmur(title: "The last transport... is away! 🚀", backgroundColor: murmurColor)
Whistle(murmur)

More info about Whisper can be found at git.io/whisper

Topics

#159: Swift Shortcuts 💇

Topics

Today we'll begin checking out some syntactic niceties available in Swift. These are tricks that can help make our code more readable, and can often make it easier to reason about. Let's get started:

Omitting Types

The Swift type system is pretty great. As long as the compiler can infer the type, we can simply leave it out when calling static functions:

struct Theme {
  let titleColor: UIColor
  static let currentTheme = Theme(titleColor: .blackColor())
}

let nightMode = Theme(titleColor: .darkGrayColor())

This trick also works just as well for static properties:

let cell = ThemeTableViewCell(theme: .currentTheme)

Shorthand Argument Names

We can use a $x syntax to reference closure arguments:

spaceships.sort { $0.name > $1.name }

Trailing Closures

Many functions accept a closure as their last parameter:

func changeTheme(theme: Theme, completion: () -> ())

In these cases, we can call them with this shorter syntax:

Theme.changeTheme(dayMode) { /* */ }

Nil coalescing

The ?? operator offers us a way to express a sort of "fallback" relationship between two statements. When the first statement is nil, it "falls back" to the second.

let cellTitle = trooper.nickname ?? trooper.troopID

At a technical level this returns either an unwrapped optional, or the value on the right, which can't be an optional.

Today we're looking at another great library from Hyper called Pages. It's essentially a convenience wrapper on top of UIPageViewController (previously covered in Bite #55). It makes working with paged view controllers a bit more friendly. Let's begin:

We'll start by composing a PagesController. This will be the view controller that contains the other view controllers:

let pagesVC = PagesController([shipsVC, stormtroopersVC])

pagesVC.enableSwipe = true
pagesVC.showBottomLine = false
pagesVC.showPageControl = false

We use a few properties to configure the look and feel and behavior we want, then we can use the view controller like normal.

Pages has some awesome convenience functions for programmatically scrolling to pages:

pagesVC.goTo(1) // go to page at index 1
pagesVC.next() // go forward 1 page
pagesVC.previous() // go back 1 page

We can also easily add view controller pages on the fly:

pagesVC.add([resistanceBasesVC, jediTemplesVC])

Last but not least, Pages is quite configurable offering properties for customizing not only the look and feel, but also behaviors such as whether or not changing view controllers affects the title shown in navigation bar of the navigation controller containing the pages.

More info about Pages can be found at git.io/pages

We've covered using UIImagePickerController to allow users to capture photos or select them from their library in Bite #83.

This is great for some situations, but often we'll want to offer our users a few more features and a little extra usability polish.

Today we'll look at a library called ImagePicker from Hyper. It's absolutely packed with features and has a super slick interface. Let's check it out:

ImagePicker is incredibly simple to use, It's just a view controller:

let imagePickerController = ImagePickerController()
imagePickerController.delegate = self

presentViewController(imagePickerController, animated: true, completion: nil)

We'll be notified via delegate functions as the user selects/takes photos:

func doneButtonDidPress(images: [UIImage]) {
  // TODO: Process images
  dismissViewControllerAnimated(true, completion: nil)
}

We can customize colors, fonts, and even the text shown in labels using a handy configuration struct filled with static properties:

Configuration.doneButtonTitle = "Upload"

More info about ImagePicker can be found at git.io/imagepicker

Today we'll check out a library called AwesomeCache by Alexander Schuch that caches data in-memory and on disk. Let's do it.

AwesomeCache can be interacted with in a few different ways. Let's start by creating a cache:

let cache = try! Cache<NSString>(name: "photos")

We can store values in the cache like this:

cache.setObject(
  responseString, 
  forKey: "a-unique-cache-key",
  expires: .Seconds(300)
)

If we're not setting an expiration time, we can use this shorthand:

cache["a-unique-cache-key"] = "Hello"

We can retrieve values from the cache in a similar way:

let cachedResponse = cache["photos.all"]

One of the handiest features of AwesomeCache is how it can help cache API responses (or any async code really). Here's how it works:

cache.setObjectForKey("photos.all", cacheBlock: { success, failure in
  self.requestLatestPhotos({ response in
    success(response, .Seconds(300))
  }, failure: { error in
    failure(error)
  })
}, completion: { object, isLoadedFromCache, error in
  if let object = object {
    // object is now cached, and ready to use
  }
})

If a value already exists in the cache for the given key, the completion** closure** is called right away. Otherwise, the cacheBlock closure is called. Inside the cacheBlock we call our custom own API code, then tell AwesomeCache if we succeeded or failed.

More info about AwesomeCache can be found at git.io/awesomecache

Weekly Sponsor: Buddybuild 🤖🛠

A huge continued thanks Buddybuild for sponsoring this week's Bites!

Buddybuild is the simplest and fastest way to automate our iOS continuous integration and continuous deployment workflows (and much, much more). Let's take a look:

Buddybuild ties together and automates: building, testing, deploying and gathering feedback for our apps. Let's try it.

We'll sign in with Github, and Buddybuild will ask us to choose the repository that contains the app we want to use with Buddybuild.

Next, Buddybuild will pull down our code and look for apps and schemes in our repo, and begin to build our app. We don't have to configure anything or write any scripts, Buddybuild takes care of everything automatically. 🤖

Buddybuild will now build and run our tests each time we push to Github, and we still haven't configured a thing by hand, neat!

Let's continue by importing our certificates and profiles. Buddybuild provides a simple way to do this. We just need to copy/paste and run the command they provide, and all the right files will be securely uploaded. 🔒

Next, we can invite testers, and they can register on their devices. We can even connect our iTunes Connect accounts so we never have to manage new devices, UDIDs, profiles or signing identities again. New testers and their devices will be automatically provisioned on our behalf!

Now, we can now instantly deploy to testers on every build, every night, or on demand.

Testers can provide feedback by taking a screenshot. Buddybuild will kick in and show them a slick custom UI for graphically annotating and sending feedback notes. We'll also get reports of any crashes with the exact line they occurred on.

Last but not least, Buddybuild integrates with tons of services like GitHub, BitBucket, GitLab, Slack, JIRA, Pivotal Tracker, Slack, HipChat, and more.

Buddybuild is an incredible tool that's absolutely packed with great features, try it right now with your own apps at buddybuild.com!

Page 21 of 38