My best iOS library in 2019 – R.swift

Of all the iOS libraries I got to know about in the year 2019, R.swift happens to be at the top, for me.

Coming from an android development background, I understand the ease that comes from being able to access drawables (images), colors, fonts, etc simply by using R.drawable.something, R.font.myFont or R.color.colorPrimary. This stuff just makes your life easier as a developer. However, as a native iOS developer, to reference an image, font, color or instantiate a ViewController, you basically have to do something like:

//Color
let color = UIColor(hexString: "#59aee9")

//Image
imageView.image = UIImage(named: "BackgroundImage")

//Font
let customFont = UIFont(name: "Poppins", size: 14)

//Instantiating ViewController
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let vc = storyboard.instantiateViewController(withIdentifier: "ViewController")

Should we talk about errors that come from a typo or even errors that come from a change in Identifiers and so on? These can put you in a lot of unnecessary trouble. Imagine someone mistakenly changing an image name from BackgroundImage to backgroundImage, such a simple mistake might cause your image not to be displayed. There are lots more other errors that could come from having to hard-code these texts this way. But there is a solution! What if we can have a fully typed, autocompleted code that has compile-time check which would make sure these images, fonts, colors, etc are present and well-referenced right at compile-time? This is exactly where R.swift comes in.

With R.swift, you get strong typed, autocompleted resources like images, fonts and segues in your Swift projects.

It makes your code that uses resources:

  • Fully typed, less casting and guessing what a method will return
  • Compile-time checked, no more incorrect strings that make your app crash at runtime
  • Autocompleted, never have to guess that image name again.

It is available for installation using Cocoapods, Mint or using the Swift Package Manager. You can find the installation guide here.

While installation is settled, let’s check out some examples to see how it works:

Images
//Vanilla
let settingsIcon = UIImage(named: "settings-icon")

//R.swift
let settingsIcon = R.image.settingsIcon()
Custom Fonts
//Vanilla
let lightFontTitle = UIFont(name: "Acme-Light", size: 22)

//R.swift
let lightFontTitle = R.font.acmeLight(size: 22)
Resource files
//Vanilla
let jsonURL = Bundle.main.url(forResource: "seed-data", withExtension: "json")

//R.swift
let jsonURL = R.file.seedDataJson()
Colors
//Vanilla
view.backgroundColor = UIColor(named: "primary background")

//R.swift
view.backgroundColor = R.color.primaryBackground()
Localized strings
//Vanilla
let welcomeMessage = NSLocalizedString("welcome.message", comment: "")

//R.swift
let welcomeMessage = R.string.localizable.welcomeMessage()
Storyboards
//Vanilla
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let settingsController = storyboard.instantiateViewController(withIdentifier: "settingsController") as? SettingsController

//R.swift
let settingsController = R.storyboard.main.settingsController()
Segues
//Vanilla
performSegue(withIdentifier: "openSettings", sender: self)

//R.swift
performSegue(withIdentifier: R.segue.overviewController.openSettings, sender: self)
Nibs
//Vanilla
let customViewNib = UINib(nibName: "CustomView", bundle: nil)

//R.swift
let customViewNib = R.nib.customView()
Reusable table view cells
//Vanilla
class FaqAnswerController: UITableViewController {
  override func viewDidLoad() {
    super.viewDidLoad()
    let textCellNib = UINib(nibName: "TextCell", bundle: nil)
    tableView.register(textCellNib, forCellReuseIdentifier: "TextCellIdentifier")
  }

  override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let textCell = tableView.dequeueReusableCell(withIdentifier: "TextCellIdentifier", for: indexPath) as! TextCell
    textCell.mainLabel.text = "Hello World"
    return textCell
  }
}
//R.swift
class FaqAnswerController: UITableViewController {
  override func viewDidLoad() {
    super.viewDidLoad()
    tableView.register(R.nib.textCell)
  }

  override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let textCell = tableView.dequeueReusableCell(withIdentifier: R.reuseIdentifier.textCell, for: indexPath)!
    textCell.mainLabel.text = "Hello World"
    return textCell
  }
}
Reusable collection view cells
//Vanilla
class RecentsController: UICollectionViewController {
  override func viewDidLoad() {
    super.viewDidLoad()
    let talkCellNib = UINib(nibName: "TalkCell", bundle: nil)
    collectionView?.register(talkCellNib, forCellWithReuseIdentifier: "TalkCellIdentifier")
  }

  override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
    let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "TalkCellIdentifier", for: indexPath) as! TalkCell
    cell.configureCell("Item \(indexPath.item)")
    return cell
  }
}
//R.swift
class RecentsController: UICollectionViewController {
  override func viewDidLoad() {
    super.viewDidLoad()
    collectionView?.register(R.nib.talkCell)
  }

  override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
    let cell = collectionView.dequeueReusableCell(withReuseIdentifier: R.reuseIdentifier.talkCell, for: indexPath)!
    cell.configureCell("Item \(indexPath.item)")
    return cell
  }
}

I’m sure you would have seen how easy some of your works would become, using this R.swift library. Why not give it a try? Trust me, you’d feel like refactoring all your code once you see it at work. ?