📱 UIKit Fundamentals
Essential UIKit concepts and patterns for iOS development
7 min read
December 25, 2023
UIKit Basics
Understanding UIKit fundamentals is essential for iOS development, even in the SwiftUI era.
1. View Controllers
class UserViewController: UIViewController {
@IBOutlet weak var tableView: UITableView!
@IBOutlet weak var nameLabel: UILabel!
private var users: [User] = []
override func viewDidLoad() {
super.viewDidLoad()
setupUI()
loadUsers()
}
private func setupUI() {
title = "Users"
navigationItem.rightBarButtonItem = UIBarButtonItem(
barButtonSystemItem: .add,
target: self,
action: #selector(addUserTapped)
)
tableView.delegate = self
tableView.dataSource = self
tableView.register(UserCell.self, forCellReuseIdentifier: "UserCell")
}
@objc private func addUserTapped() {
// Handle add user action
}
private func loadUsers() {
// Load users from API
}
}
2. Auto Layout
class CustomView: UIView {
private let titleLabel = UILabel()
private let subtitleLabel = UILabel()
private let actionButton = UIButton(type: .system)
override init(frame: CGRect) {
super.init(frame: frame)
setupViews()
setupConstraints()
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
private func setupViews() {
addSubview(titleLabel)
addSubview(subtitleLabel)
addSubview(actionButton)
titleLabel.text = "Title"
titleLabel.font = UIFont.boldSystemFont(ofSize: 18)
subtitleLabel.text = "Subtitle"
subtitleLabel.font = UIFont.systemFont(ofSize: 14)
subtitleLabel.textColor = .gray
actionButton.setTitle("Action", for: .normal)
actionButton.backgroundColor = .systemBlue
actionButton.setTitleColor(.white, for: .normal)
actionButton.layer.cornerRadius = 8
}
private func setupConstraints() {
titleLabel.translatesAutoresizingMaskIntoConstraints = false
subtitleLabel.translatesAutoresizingMaskIntoConstraints = false
actionButton.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
// Title label constraints
titleLabel.topAnchor.constraint(equalTo: topAnchor, constant: 16),
titleLabel.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 16),
titleLabel.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -16),
// Subtitle label constraints
subtitleLabel.topAnchor.constraint(equalTo: titleLabel.bottomAnchor, constant: 8),
subtitleLabel.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 16),
subtitleLabel.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -16),
// Action button constraints
actionButton.topAnchor.constraint(equalTo: subtitleLabel.bottomAnchor, constant: 16),
actionButton.centerXAnchor.constraint(equalTo: centerXAnchor),
actionButton.widthAnchor.constraint(equalToConstant: 120),
actionButton.heightAnchor.constraint(equalToConstant: 44),
actionButton.bottomAnchor.constraint(equalTo: bottomAnchor, constant: -16)
])
}
}
3. Table Views
extension UserViewController: UITableViewDataSource, UITableViewDelegate {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return users.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "UserCell", for: indexPath) as! UserCell
let user = users[indexPath.row]
cell.configure(with: user)
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: true)
let user = users[indexPath.row]
// Navigate to user detail
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 60
}
}
class UserCell: UITableViewCell {
private let nameLabel = UILabel()
private let emailLabel = UILabel()
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
setupViews()
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
private func setupViews() {
contentView.addSubview(nameLabel)
contentView.addSubview(emailLabel)
nameLabel.font = UIFont.boldSystemFont(ofSize: 16)
emailLabel.font = UIFont.systemFont(ofSize: 14)
emailLabel.textColor = .gray
// Setup constraints...
}
func configure(with user: User) {
nameLabel.text = user.name
emailLabel.text = user.email
}
}
4. Navigation
class MainViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
setupNavigation()
}
private func setupNavigation() {
// Programmatic navigation
let userVC = UserViewController()
let navController = UINavigationController(rootViewController: userVC)
present(navController, animated: true)
// Push navigation
navigationController?.pushViewController(userVC, animated: true)
// Modal presentation
let modalVC = ModalViewController()
modalVC.modalPresentationStyle = .pageSheet
present(modalVC, animated: true)
}
}
// Navigation delegate
extension MainViewController: UINavigationControllerDelegate {
func navigationController(_ navigationController: UINavigationController,
willShow viewController: UIViewController,
animated: Bool) {
// Handle navigation events
}
}
5. Delegates and Protocols
protocol UserSelectionDelegate: AnyObject {
func didSelectUser(_ user: User)
func didDeselectUser(_ user: User)
}
class UserListViewController: UIViewController {
weak var delegate: UserSelectionDelegate?
private var selectedUsers: Set = []
private func handleUserSelection(_ user: User) {
if selectedUsers.contains(user) {
selectedUsers.remove(user)
delegate?.didDeselectUser(user)
} else {
selectedUsers.insert(user)
delegate?.didSelectUser(user)
}
}
}
class ParentViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let userListVC = UserListViewController()
userListVC.delegate = self
addChild(userListVC)
view.addSubview(userListVC.view)
userListVC.didMove(toParent: self)
}
}
extension ParentViewController: UserSelectionDelegate {
func didSelectUser(_ user: User) {
print("Selected user: \(user.name)")
}
func didDeselectUser(_ user: User) {
print("Deselected user: \(user.name)")
}
}
6. Best Practices
✅ Do's
- Use weak references for delegates
- Implement proper memory management
- Use Auto Layout for responsive design
- Follow MVC or MVVM patterns
- Test your view controllers
❌ Don'ts
- Don't retain delegates strongly
- Don't perform heavy operations on main thread
- Don't ignore memory warnings
- Don't mix UI and business logic