UIKit is a framework for building graphical interfaces in iOS and macOS applications. The toolkit includes UIView, UIViewController, control elements, and the Auto Layout system, enabling the creation of adaptive and interactive screens. According to Apple Developer Documentation (2025), UIKit contains over 200 classes for working with windows, views, animations, gestures, and text — it is the foundation of all iPhone and iPad applications.
Key Takeaways
UIKit is a framework from Apple that provides classes for creating and managing user interfaces on iOS, iPadOS, and macOS (via Mac Catalyst). It works on top of Core Animation, Core Graphics, and Quartz Core, abstracting low-level rendering into high-level objects — buttons, labels, images, and containers. UIKit debuted with iPhone OS 1 in 2007 and remains the primary framework for iOS development alongside SwiftUI.
The framework follows an imperative approach: the developer creates instances of UIButton, UILabel, UIImageView classes, sets their properties (color, font, position), and adds them to the view hierarchy via addSubview. Every interface change is performed explicitly — no magic updates behind the scenes. This distinguishes UIKit from declarative frameworks like SwiftUI, where the state description automatically redraws the interface.
The framework includes several categories of classes. UIView is the base element from which all visual components inherit. UIWindow is the top-level container through which views are displayed on screen. UIViewController manages a set of views and responds to screen rotations, keyboard appearances, and system notifications. UIApplication is the entry point that processes touch events and button presses.
For text, UILabel (static text), UITextField (single-line input), and UITextView (multi-line input) are used. For buttons — UIButton, including system, custom, and SF Symbols iconography. For navigation — UINavigationController, UITabBarController, and UISplitViewController. In total, UIKit has over 200 public classes.
UIKit architecture is built on layers: each layer is responsible for its own aspect of display. At the lowest level is Core Graphics — the rendering engine for paths, text, and images. Above it is Core Animation, which manages layer composition (CALayer) and animations between states. UIKit builds an object-oriented API on top of them: UIView, UIViewController, and UIResponder.
Every application has a view hierarchy — a tree whose root is the UIWindow. Below it is the root UIViewController, its view, and nested subviews inside. Touch events propagate along the responder chain: from the deepest nested view to its parents and up to UIApplication. If no object handles the touch, it is ignored.
Each UIView contains a CALayer that handles pixel rendering on screen. The view manages touches and accessibility; the layer handles graphics — shadow, cornerRadius, border, transform. This separation allows heavy graphics to be offloaded to a separate thread (render server) without blocking the main thread. Apple recommends working directly with CALayer if more than 200 views are on screen — this reduces CPU load.
The responder chain starts with the object that first receives a touch event. If it does not handle the event (the touchesBegan method is not overridden), the event moves to the next responder in the chain: next, superview, next responder, UIViewController, UIWindow, UIApplication, App Delegate. This allows global gestures and keyboard events to be intercepted at the scene level without adding a handler to every view.
Each UIViewController goes through a strictly defined sequence of events. The lifecycle includes phases: initialization, view loading, appearing on screen, layout update on rotation, hiding, leaving the screen, and memory deallocation. The developer overrides the corresponding methods to execute custom code at each stage.
class ProfileViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
setupUI()
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
loadUserProfile()
}
override func viewDidDisappear(_ animated: Bool) {
super.viewDidDisappear(animated)
clearCache()
}
}
In viewDidLoad, the interface is configured — subviews are created, constraints are set, delegates are subscribed. In viewWillAppear, operations before display are performed: loading fresh data from the network, updating values. viewDidDisappear is the place to unsubscribe from notifications and clean up temporary data. Calling super is mandatory in all overrides, otherwise the event chain breaks.
In older iOS versions, the viewDidUnload method existed and was called when memory was low. Since iOS 6, the method has been removed — UIKit now automatically unloads views of controllers when they are not visible. The developer only needs to declare all view references as weak so that ARC can properly free memory upon receiving a system warning.
UIKit supports two types of transitions: segue (via Storyboard) and programmatic navigation through UINavigationController. A programmatic transition looks like this: navigationController?.pushViewController(detailVC, animated: true). In this case, the detailVC lifecycle proceeds as usual — viewDidLoad is called once, viewWillAppear is called each time it appears.
Auto Layout is a positioning system based on mathematical relationships (constraints). Instead of hard-coded X and Y coordinates, the developer describes rules: “the button is to the right of the label with a 16pt offset” or “the view stretches across the screen width with 20pt margins on the left and right.” The system solves the resulting system of equations at runtime, adapting the interface to any screen size.
Constraints can be set in Interface Builder (via drag-and-drop) or programmatically in Swift. Each constraint is an instance of the NSLayoutConstraint class with parameters: firstItem, firstAttribute, relation, secondItem, secondAttribute, multiplier, constant. Constraints are activated via isActive = true or in bulk via NSLayoutConstraint.activate().
With the introduction of iPhone X (2017), Apple introduced the Safe Area — the screen area free from the notch, rounded corners, and home bar indicator. Constraints should be attached to view.safeAreaLayoutGuide, not to view. Layout Margins add internal view padding, defaulting to 8pt or 16pt depending on context. Using safeAreaLayoutGuide ensures correct display on all iPhone and iPad generations.
Auto Layout supports animation by changing constraint constants. Simply update the constant of a constraint and call UIView.animate with layoutIfNeeded inside the animation block. The system smoothly recalculates the position of all views in the hierarchy. This technique is used for expandable blocks, adaptive keyboard panels, and screen orientation changes.
UITableView and UICollectionView are two powerful UIKit tools for displaying lists and grids. UITableView is suitable for vertical single-column lists (chat, settings, news feed). UICollectionView is for grids, horizontal lists, carousels, and custom layouts (gallery, products, calendar). Both classes use the delegation pattern to separate data from appearance.
The data source is the UITableViewDataSource protocol with required methods numberOfRowsInSection and cellForRowAt. The UITableViewDelegate handles cell taps, row heights, and scroll events. The reuse identifier mechanism reuses cells that have scrolled off screen, which is critical for performance on large lists.
class ContactsViewController: UITableViewController {
private let contacts = ["Anna", "Boris", "Victor"]
override func viewDidLoad() {
super.viewDidLoad()
tableView.register(UITableViewCell.self,
forCellReuseIdentifier: "cell")
}
override func tableView(_ tableView: UITableView,
numberOfRowsInSection section: Int) -> Int {
return contacts.count
}
override func tableView(_ tableView: UITableView,
cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell",
for: indexPath)
var content = cell.defaultContentConfiguration()
content.text = contacts[indexPath.row]
cell.contentConfiguration = content
return cell
}
}
The example shows a minimal controller for displaying an array of strings. The cell is configured via UIListContentConfiguration — a modern API (iOS 14+) that replaced the deprecated textLabel and detailTextLabel. Registering the cell class in viewDidLoad is mandatory, otherwise the application will crash with a runtime exception.
Starting with iOS 13, Apple recommends UICollectionViewCompositionalLayout for building complex layouts. The developer describes the section, group, item, and their sizes declaratively — resulting in a grid with arbitrary geometry: a strip, 2x2 grid, carousel, or ornament. Compositional Layout has replaced the outdated UICollectionViewFlowLayout for all new projects. Combined with DiffableDataSource, updating a collection is reduced to a single apply(snapshot) call, and change animations are performed automatically.
Below are two practical examples of using UIKit in real-world tasks: creating a custom view with shadow and rounded corners, and handling a swipe gesture to delete an item from a list.
extension UIView {
func applyCardStyle() {
layer.cornerRadius = 12
layer.shadowOpacity = 0.15
layer.shadowRadius = 8
layer.shadowOffset = CGSize(width: 0, height: 2)
layer.masksToBounds = false
}
}
@objc private func handleSwipe(_ gesture: UISwipeGestureRecognizer) {
guard let swipedView = gesture.view else { return }
UIView.animate(withDuration: 0.3) {
swipedView.alpha = 0
swipedView.transform = CGAffineTransform(translationX: 300, y: 0)
} completion: { _ in
swipedView.removeFromSuperview()
}
}
The applyCardStyle extension adds shadow and rounded corners to any view — useful for product cards, profiles, and notifications. The handleSwipe method with animation deletes an item when the user swipes right on it. The handler is added to the view via addGestureRecognizer with a UISwipeGestureRecognizer(direction: .right) configuration. Setting masksToBounds = false is important to prevent the shadow from being clipped by the view bounds.
For more complex interfaces, use UIStackView — a container that automatically distributes nested views horizontally or vertically. Stack View simplifies layout: no need to set constraints for each element, just one constraint for the stack itself.
Frequently Asked Questions
Frame is a rectangle in the superview's coordinates (position + size). Bounds is a rectangle in the view's own coordinates (always starts at 0,0). Frame changes on rotate and scale; bounds does not.
UIKit automatically unloads views of hidden controllers. The developer only needs to declare view properties as weak var so that ARC can free memory upon a system warning.
For new projects, Apple recommends SwiftUI. If the project uses UIKit — use XIB for individual screens or programmatic layout via SnapKit. Storyboard creates merge conflicts and slows down the build.
Use UIColor with traitCollection support: UIColor { $0.userInterfaceStyle == .dark ? ... : ... }. Enable Dark Mode in Info.plist with the UIUserInterfaceStyle key.
UIStackView automatically calculates the positions and sizes of nested views based on alignment, distribution, and spacing. It reduces constraint code by 60–80% and simplifies adaptation to different screens.
Summary
We will develop a mobile application turnkey
IT Sectr creates iOS and Android applications for startups and businesses since 2017. We will advise you and propose the best solution.
Read also