4 Swift Libraries You Didn’t Know You Needed
Table of contents
Photo by Maxwell Nelson on Unsplash
Swift is a powerful and intuitive programming language for iOS, iPadOS, macOS, tvOS, and watchOS. It offers modern features such as generics, protocols, closures, and automatic memory management that make writing high-performance and readable code easier and more fun1. The Swift standard library provides a base layer of functionality for Swift programs, including fundamental data types, collections, input/output, concurrency, and more2. However, sometimes you may need more than what the standard library offers. In this article, we will explore four lesser-known but useful Swift libraries that can help you with some common tasks in iOS development.
1. SnapKit
SnapKit is a DSL (domain-specific language) to make Auto Layout easy on both iOS and macOS3. Auto Layout is a system that lets you create adaptive user interfaces that can respond to different screen sizes and orientations. However, using Auto Layout programmatically can be verbose and cumbersome. SnapKit simplifies this process by providing a concise and expressive syntax that allows you to define constraints with less code.
For example, suppose you want to create a simple view with a label and a button that are centered horizontally and vertically in their superview. Using Auto Layout directly, you would need to write something like this:
let label = UILabel()
label.text = "Hello World"
label.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(label)
let button = UIButton()
button.setTitle("Tap Me", for: .normal)
button.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(button)
let centerXConstraint = NSLayoutConstraint(item: label,
attribute: .centerX,
relatedBy: .equal,
toItem: view,
attribute: .centerX,
multiplier: 1,
constant: 0)
let centerYConstraint = NSLayoutConstraint(item: label,
attribute: .centerY,
relatedBy: .equal,
toItem: view,
attribute: .centerY,
multiplier: 1,
constant: -50)
let buttonCenterXConstraint = NSLayoutConstraint(item: button,
attribute: .centerX,
relatedBy: .equal,
toItem: view,
attribute: .centerX,
multiplier: 1,
constant: 0)
let buttonTopConstraint = NSLayoutConstraint(item: button,
attribute: .top,
relatedBy: .equal,
toItem: label,
attribute: .bottomMargin
multiplier:)
//...
Using SnapKit, you can achieve the same result with much less code:
let label = UILabel()
label.text = "Hello World"
view.addSubview(label)
let button = UIButton()
button.setTitle("Tap Me", for: .normal)
view.addSubview(button)
label.snp.makeConstraints { make in
make.centerX.equalToSuperview()
make.centerY.equalToSuperview().offset(-50)
}
button.snp.makeConstraints { make in
make.centerX.equalToSuperview()
make.top.equalTo(label.snp.bottomMargin).offset(20)
}
As you can see, SnapKit provides a fluent interface that lets you chain constraints and use operators to modify them. You can also use properties like **equalToSuperview()**
or **bottomMargin**
to avoid repeating attributes. SnapKit also handles setting **translatesAutoresizingMaskIntoConstraints**
to false for you, so you don’t have to worry about that.
SnapKit also supports updating and removing constraints dynamically. For example, if you want to change the label’s position when the button is tapped, you can do something like this:
button.addTarget(self, action: #selector(buttonTapped), for: .touchUpInside)
@objc func buttonTapped() {
label.snp.updateConstraints { make in
make.centerY.equalToSuperview().offset(50)
}
}
Or if you want to remove all constraints from the label, you can do this:
label.snp.removeConstraints()
SnapKit is a great library for anyone who prefers to use Auto Layout programmatically. It reduces boilerplate code and makes your layout code more readable and maintainable.
Photo by Lautaro Andreani on Unsplash
2. Alamofire
Alamofire is an elegant and powerful HTTP networking library written in Swift1. It provides a convenient way to perform common networking tasks such as making requests, uploading files, downloading data, handling responses, validating status codes, parsing JSON, and more.
For example, suppose you want to make a GET request to an API endpoint that returns a list of users in JSON format. Using Alamofire, you can write something like this:
import Alamofire
AF.request("https://example.com/users").responseJSON { response in
switch response.result {
case .success(let value):
print("JSON: \(value)")
// handle JSON data here
case .failure(let error):
print(error)
// handle error here
}
}
As you can see, Alamofire provides a simple and expressive syntax that lets you chain methods and closures to perform network operations. You can also customize your requests with parameters, headers, encoding, authentication, and more. You can also handle different types of responses, such as JSON, XML, property list, image, or custom data.
Alamofire also supports uploading and downloading files with progress tracking and resume capabilities. For example, if you want to upload an image to a server using multipart form data encoding, you can write something like this:
import Alamofire
let image = UIImage(named: "photo.jpg")
let imageData = image?.jpegData(compressionQuality: 0.8)
AF.upload(multipartFormData: { multipartFormData in
multipartFormData.append(imageData!, withName: "image", fileName: "photo.jpg", mimeType: "image/jpeg")
}, to: "https://example.com/upload")
.uploadProgress { progress in
print("Upload Progress: \(progress.fractionCompleted)")
}
.responseJSON { response in
print(response.result)
// handle response here
}
As you can see, Alamofire provides a convenient way to encode and send multipart form data with a single method call. You can also use closures to track the upload progress and handle the response.
Alamofire is a great library for anyone who needs to perform HTTP networking tasks in their iOS apps. It simplifies common tasks and makes your networking code more readable and maintainable.
3. Realm
Realm is a cross-platform mobile database that is fast, lightweight, and easy to use. It provides an alternative to SQLite and Core Data that can save you from writing lots of boilerplate code and improve your app’s performance.
For example, suppose you want to create a simple model class for a user that has properties like name, email, age, and gender. Using Core Data, you would need to create an entity in a data model file, add attributes with types and constraints, generate a class file, and write code to create, fetch, update, and delete instances of the class. Using Realm, you only need to write a few lines of code:
import RealmSwift
class User: Object {
@Persisted var name: String = ""
@Persisted var email: String = ""
@Persisted var age: Int = 0
@Persisted var gender: String = ""
}
As you can see, Realm uses a subclass of **Object**
to define a model class. You can also use the **@Persisted**
property wrapper to declare properties that are stored in the database. Realm supports most basic types such as **String**
, **Int**
, **Bool**
, **Date**
, **Data**
, as well as optional types, collections, and relationships.
To use Realm in your app, you need to get an instance of **Realm**
that represents a Realm database. You can use the default Realm that is provided by Realm for each application or user:
let realm = try! Realm()
Note that this may throw an error if the Realm file is corrupted or inaccessible. In this tutorial, you will use force unwrapping for simplicity, but you should handle errors properly in a real app.
Once you have a **Realm**
instance, you can perform various operations on it. For example, if you want to create a new user and save it to the database, you can write something like this:
let user = User()
user.name = "John Doe"
user.email = "john.doe@example.com"
user.age = 25
user.gender = "male"
try! realm.write {
realm.add(user)
}
As you can see, Realm uses transactions to ensure data integrity and concurrency control. You need to wrap any write operation inside a **realm.write**
block.
To query data from Realm, you can use methods like **objects(_:)**
, which returns all objects of a given type:
let users = realm.objects(User.self)
This returns a collection of users that is auto-updating and live. This means that any changes made to the users in the database will be reflected in this collection automatically.
You can also filter and sort the results using methods like **filter(_:)**
and **sorted(byKeyPath:)**
. For example,
let femaleUsers = users.filter("gender == 'female'")
let sortedUsers = users.sorted(byKeyPath: "age", ascending: false)
These methods also return auto-updating collections that reflect the current state of the database.
To update data in Realm, you can either modify an existing object inside a write transaction, or use methods like **create(_:value:update:)**
or **add(_:update:)**
to create or update an object with a given value. For example,
try! realm.write {
user.name = "Jane Doe"
user.email = "jane.doe@example.com"
}
// Or
try! realm.write {
realm.create(User.self, value: ["taskid": user.taskid, "name": "Jane Doe", "email": "jane.doe@example.com"], update: .modified)
}
//Both ways will update the user’s name and email in the database.
//To delete data from Realm, you can use methods like **delete(_:)** or **deleteAll()**. For example,
try! realm.write {
realm.delete(user)
}
// Or
try! realm.write {
realm.deleteAll()
}
The first way will delete a specific user from the database, while the second way will delete all objects from the database.
Realm is a great library for anyone who needs a fast and easy-to-use database solution for their iOS apps. It saves you from writing lots of boilerplate code and improves your app’s performance.
4. Lottie
Lottie is a library that renders After Effects animations in real time, allowing apps to use animations as easily as they use static images. Lottie supports both iOS and Android platforms and can play animations natively using native rendering APIs.
For example, suppose you want to add a loading animation to your app. Using Lottie, you only need to download a JSON file that contains the animation data from LottieFiles, a website that provides free animations created by designers around the world. Then you can write something like this:
import Lottie
let animationView = AnimationView(name: "loading")
animationView.frame = CGRect(x: 0, y: 0, width: 100, height: 100)
animationView.center = self.view.center
animationView.contentMode = .scaleAspectFill
view.addSubview(animationView)
animationView.play()
As you can see, Lottie provides a simple way to create an animation view with a given name that matches the JSON file name. You can also customize the frame, center, content mode, and other properties of the animation view. Then you can use methods like **play()**
, **pause()**
, or **stop()**
to control the animation.
Lottie also supports adding animation views using Interface Builder. You can drag and drop a UIView to your storyboard or xib file, change its class to **AnimationView**
, and set its module to **Lottie**
. Then you can use the Attributes Inspector to set the animation name, loop mode, speed, and other properties.
Lottie is a great library for anyone who wants to add stunning animations to their iOS apps. It allows you to use animations created by designers in After Effects without writing any code.
Conclusion
In this article, you learned about four unknown but useful Swift libraries for iOS development: SnapKit, Alamofire, Realm, and Lottie. These libraries can help you with some common tasks such as layout, networking, database, and animation. They can also make your code more concise, expressive, and maintainable.
Of course, there are many more Swift libraries out there that can help you with different aspects of iOS development. You can explore some of them on websites like CocoaPodsor Awesome iOS. You can also create your own libraries if you have some reusable code that you want to share with others.
I hope you enjoyed this article and learned something new. If you have any questions or feedback, please feel free to leave a comment below . Happy coding! 😊
Subscribe to my newsletter
Read articles from CS Diaries directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by