With another year of experience behind us, we bring you a handy list for every iOS developer’s collection – the curated list of the best, most important, most useful iOS libraries, updated for 2021.
If this feels like deja vu, it’s because we published top 10 iOS libraries lists in 2020, as well as the age-old article top 10 iOS libraries of 2015.
Development and testing libraries
Those articles proved a great starting point for developers looking to increase their productivity and avoid doing unnecessary work. With the same goal in mind, we’ve kept some oldies goldies on the list, but added the hottest hits of 2021. As our knowledge grows, we recognize what stands the test of time and what should be replaced with something new and innovative.
Speaking of innovation, this time around the libraries are sorted into two categories, development and testing. It might help you navigate faster if you’re looking for something specific.
We’ve also decided not to limit ourselves with a top-10 format, and just present all the libraries we believe may prove useful.
Some obligatory side notes
We’ve said it time and time again: It is really important to use third-party libraries responsibly. Here are some points that should help you decide whether a library is worth importing to your project:
- Make sure that the libraries you want to use are actively maintained and supported. Working on a long-term project could prove troublesome if it stops compiling because some Swift or iOS change broke the libraries.
- You should utilise a great part of the libraries in your projects to make it worth the time, not just a small part of it. As we mentioned before: “Don’t use an excavator where a shovel would suffice.”
It should also be noted that this list was created by surveying our recent projects and needs, and only contains sources or opinions of the iOS team at Infinum.
Third-party development libraries
RxSwift / RxCocoa
The Swift version of Rx tries to port as many concepts from the original version as possible, but some of them have been adapted for a more pleasant and performant integration with the iOS/macOS environment.
Like the original Rx, its intention is to enable an easy composition of asynchronous operations and event/data streams. KVO observing, async operations and streams are all unified under the abstraction of sequence. This is the reason why Rx is so simple, elegant and powerful.
Here’s a simple example of how RxSwift can be used to create a logic for enabling a login button that checks two things – whether the username and password have both been entered, and if the password is of appropriate minimum length.
let name = nameTextField.rx.text.asDriver()
let password = passwordTextField.rx.text.asDriver()
let isEnabled = Driver
.combineLatest(
name,
password
) { !$0.isEmpty && $1.count >= 6 }
isEnabled
.drive(loginButton.rx.isEnabled)
.disposed(by: disposeBag)
This is just scratching RxSwift’s surface, but you can already see how it can make your life easier. RxSwift has a steeper learning curve than most libraries you could include in your projects, but once you get the hang of it, you’ll be thankful you did and will probably never look back.
The other library that RxSwift goes hand in hand with is RxCocoa. It is built around the Cocoa API, making it easier to use in a reactive manner. For example, check out how easy it is to catch all button tap events, without dealing with IBActions.
let buttonTapSignal = loginButton.rx.tap.asSignal()
buttonTapSignal
.emit()
.disposed(by: disposeBag)
Note: Combine will probably start slowly sunsetting RxSwift at some point. However, since it requires iOS 13 as the minimum OS version, we’re still not at a point where we can start using it in most projects. Until then, RxSwift will prevail.
SwiftLint
SwiftLint is a tool used to enforce Swift style and conventions, loosely based on GitHub’s Swift Style Guide.
Its rule list is quite extensive, and covers pretty much everything you would want to keep track of in a well-maintained project. It also has the option to disable rules per-file or even per-line, but use those responsibly. Silencing a warning about a 700-line file or a too long method is maybe not the best tactic.
Alamofire
Alamofire is an elegant and composable way to interface to HTTP network requests. It builds on top of Apple’s URL Loading System provided by the Foundation framework. At the system’s core are the URLSession and URLSessionTask subclasses. Alamofire wraps these APIs, and many others, in an easy-to-use interface and provides a variety of functionalities necessary for modern application development using HTTP networking.
AF
.request("https://your.api.url")
.validate()
.responseDecodable(of: SomeDecodableObject.self) { (response) in
guard let object = response.value else { return }
print(object) // Your object, decoded and ready to use.
}
From top to bottom, you request the endpoint, validate the response by ensuring the response returned an HTTP status code in the range 200–299 and decode the response into your data model. Easy peasy.
Lottie
Let’s be honest, animations in an application make a huge difference. They grasp the user’s attention and steer them through your app’s flow, all the while providing a fun and memorable experience. Since creating animations by hand using UIView or CoreGraphics animations can prove to be quite challenging and time-consuming, Lottie provides us with a perfect tool to incorporate designers’ creations into our applications. Lottie loads and renders animations and vectors exported in the bodymovin JSON format. Bodymovin JSON can be created and exported from After Effects with bodymovin, Sketch with Lottie Sketch Export, and from Haiku.
override func viewDidLoad() {
super.viewDidLoad()
startAnimating()
}
func startAnimating(){
animationView.setAnimation(named: "bird_flying") // "bird_flying" is an example animation that can be found here: https://lottiefiles.com/17655-bird-flying
animationView.play()
}
After importing Lottie into your project, this is all the code needed to add a beautiful animation to your app. Quite a timesaver.
SVProgressHUD
If there was an award for libraries called “Simple integration, huge benefit”, I would undoubtedly hand it out to SVProgressHUD. Basically, all it does is display the progress of an ongoing task on iOS and tvOS. Using this library is as easy as calling the method;SVProgressHUD is a singleton, so all you have to do is use the methods show()
and dismiss()
.
Even though it is simple to use, it can be customized in various ways – from animation type to ring radius, icons, and it even offers haptic feedback on success, info or error statuses.
KeychainAccess
KeychainAccess is a simple Swift wrapper for Keychain that works on iOS and macOS. It makes using Keychain APIs extremely easy and much more manageable to use in Swift.
Saving data to the Keychain and retrieving it has never been easier:
// Save to the keychain
let valueToSave = "Important data"
Keychain().set(valueToSave, key: "key")
// Get from keychain
let savedValue = try? Keychain().get("key")
Kingfisher
Kingfisher is a powerful, pure-Swift library for downloading and caching images from the web. It downloads the image from its URL, sends it to both the memory cache and the disk cache, and displays it in an UIImageView, NSImageView, NSButton or UIButton. When you try to retrieve an image with the same URL later, the image will be retrieved from cache and shown immediately.
// Basic version
let url = URL(string: "https://example.com/image.png")
imageView.kf.setImage(with: url)
// SwiftUI version
import KingfisherSwiftUI
var body: some View {
KFImage(URL(string: "https://example.com/image.png")!)
}
It also provides many powerful additional options such as showing a system indicator and a placeholder image while downloading, built-in updating transitions, extensible image processing and formatting and much more. A must have if you’re working with remote images!
SnapKit
SnapKit is an Auto Layout library that simplifies writing auto layout in code, so that a minimal amount of code is needed, but without losing readability. It is type-safe by design to help you avoid programming errors while coding your user interface.
let box = UIView()
let container = UIView()
container.addSubview(box)
box.snp.makeConstraints { make in
make.size.equalTo(50)
make.center.equalTo(container)
}
It’s also very powerful when it comes to views whose constraints are updated frequently. Remaking constraints is much more pleasant than dealing with Auto Layout by hand:
func updateBoxSize(to size: CGFloat) {
box.snp.remakeConstraints { remake in
remake.size.equalTo(size)
}
}
Third-party testing libraries
Sourcery
Sourcery is a library that finally puts a stop to writing repetitive code and creates better architecture and developer workflows. One of Sourcery’s best usages comes with implementing Mocks
, and it is usually this kind of code:
<span data-es-language="c"></span>lass UserViewInterfaceMock: ViewInterface {
var setUsernameCalled = false
var setUsernameReceivedValue: String?
func setUsername(username: String) {
setUsernameCalled = true
setUsernameReceivedValue: username
}
}
With Sourcery, all you need to do is make your protocol inherit Automockable
, like in this example:
extension ViewInterface: Automockable {}
Now you know how Sourcery has been a great help to our team and it is one of our favourite libraries for generating tests.
Quick & Nimble
We’ve put these two libraries together as they usually go hand in hand. Quick is a behavior-driven development framework for Swift and Objective-C, while Nimble is used as an assertion framework that makes it easy to match expectations on tests. To get an idea how tests written with these frameworks look like, check the code below.
import Quick
import Nimble
class DolphinSpec: QuickSpec {
override func spec() {
it("is friendly") {
expect(Dolphin().isFriendly).to(beTruthy())
}
it("is smart") {
expect(Dolphin().isSmart).to(beTruthy())
}
}
}
OHHTTPStubs
OHTTPStubs is a library designed to stub network requests by using method swizzling. It works with NSURLConnection, NSURLSession, AFNetworking, Alamofire or any networking framework that uses Cocoa’s URL Loading System.
stub(
condition: { (request: URLRequest) -> Bool in
// check whether this api call should be mocked by using the response closure
// return false if it shouldn’t
return true
},
response: { _ -> OHHTTPStubsResponse in
let path = "...path_to_your_file.json"
return fixture(filePath: path, status: 200)
}
)
This library comes in handy in several situations:
- mocking different API responses while the app is in development to check if our UI handles every case correctly,
- easier integration testing by providing baked-in responses to your testing suite,
- implementing a demo mode inside your application which doesn’t reach the actual server, but uses baked-in responses.
If you’d like to learn more about implementing such a demo mode, you can check out one of our previous articles.
RxTest / RxBlocking
RxTest and RxBlocking are both parts of RxSwift. They are available via separate pods and also require separate imports.
RxTest is a great addition for testing Rx code. It comes with a TestScheduler
, which is a virtual time scheduler. RxTest gives out two types of Observables: HotObservables, which replay time specified events using test scheduler, and ColdObservables, which behave just like regular ones.
RxBlocking gives you the power of converting a regular observable sequence to a blocking observable, which blocks the thread it is running on until the sequence times out or completes. This makes it a perfect tool for testing asynchronous tasks.
func testBlocking() throws {
let observable = Observable.of(10, 20, 30)
let result = try observable.toBlocking().first()
XCTAssertEqual(result, 10)
}
Infinum’s development libraries
We also use our own libraries in most of our projects, but since these are our open-source libraries, it did not seem right to steal the spotlight from other popular third-party libraries. However, you can check them out below as well.
Prince of Versions – used for easier versioning of your applications, allows you to prompt your users to update the app to the newest version.
Locker – a lightweight library for handling sensitive data (String type) in Keychain using iOS Biometrics features
I18n – a library that allows you to localize your app much easier, by adding custom properties to UI elements and setting up available languages within the code.
Loggie – used for capturing all HTTP/S requests the app makes and showing them in a simple table view, enabling easier API debugging.
Also, be sure to check out Nuts & Bolts, Infinum iOS team’s repo containing a centralized collection of commonly shared and reused code.
Anything we forgot to include?
Do you use the same or similar libraries in your work? Or perhaps you know of other useful libraries that should be included in this list? Let us know via social media – we’re always happy to learn new things about iOS.
Until next time, happy coding!