Irbisa · Cheatsheet
UIKit Fundamentals
UIView, UIViewController lifecycle, view hierarchy, touch handling
What is
UIWindow, how does the view hierarchy start, and how is a window different from an ordinaryUIView?Walk through the
UIViewControllerlifecycle: which callbacks run once, which run on every appearance, and where do you start loading data?What is
loadView, when do you override it, and how is it different fromviewDidLoad?final class ProfileView: UIView { let nameLabel = UILabel() // builds its own subviews and constraints in init} final class ProfileViewController: UIViewController {…What is the difference between
frameandbounds, and when isbounds.originnot zero?let card = UIView(frame: CGRect(x: 20, y: 100, width: 120, height: 60))// card.frame = (20, 100, 120, 60) in the superview's coordinates// card.bounds = (0, 0, 120, 60) in its own coordinates let dot = UIView(frame: CGRect(x: 10, y: 10, width: 20, height: 20))card.addSubview(dot) // (10, 10) inside card…What are the trade-offs between storyboards, XIBs and building the UI in code?
What is the difference between
@IBOutletand@IBAction, and how does target-action connect a control to your code?final class LoginViewController: UIViewController { @IBOutlet private weak var emailField: UITextField! @IBOutlet private weak var loginButton: UIButton! private let retryButton = UIButton(type: .system) @IBAction private func loginTapped(_ sender: UIButton) {…How does
UINavigationControllerwork, and what is the difference between pushing and presenting a view controller?// Push: onto the current navigation stacknavigationController?.pushViewController(DetailViewController(id: id), animated: true)navigationController?.popViewController(animated: true) // Present: modally, with its own navigation barlet editor = UINavigationController(rootViewController: EditorViewController())…How does
UITableViewwork: what do the data source and the delegate do, and what is cell reuse?final class ContactsViewController: UITableViewController { private var names = ["Alice", "Bob", "Carol"] override func viewDidLoad() { super.viewDidLoad() tableView.register(UITableViewCell.self, forCellReuseIdentifier: "Cell")…How does
UIScrollViewwork: what arecontentSize,contentOffsetandcontentInset?final class FeedViewController: UIViewController, UIScrollViewDelegate { private let scrollView = UIScrollView() private let header = UIView() override func viewDidLoad() { super.viewDidLoad()…What is the difference between
UIImageandUIImageView, and between.scaleAspectFitand.scaleAspectFill?How do you round a view's corners and add a shadow, and why do the two conflict?
final class CardView: UIView { let content = UIView() // inner view: clips to the rounded shape override init(frame: CGRect) { super.init(frame: frame) layer.shadowColor = UIColor.black.cgColor…This label is updated from a
URLSessioncallback and the app later crashes at random. What is wrong, and how do you fix it?func loadProfile() { URLSession.shared.dataTask(with: profileURL) { data, _, _ in guard let data else { return } let profile = try? JSONDecoder().decode(Profile.self, from: data) self.nameLabel.text = profile?.name self.view.setNeedsLayout() }.resume()}How do you support Dark Mode in UIKit, and why does a layer's border colour not switch along with it?
final class BadgeView: UIView { override init(frame: CGRect) { super.init(frame: frame) backgroundColor = .secondarySystemBackground // dynamic: updates itself layer.borderWidth = 1 updateBorder()…How do you animate a view in UIKit, and how do you animate an Auto Layout constraint change?
// Expand a panel by changing its height constraintview.layoutIfNeeded() // settle pending layout firstheightConstraint.constant = isExpanded ? 240 : 88UIView.animate(withDuration: 0.3) { self.view.layoutIfNeeded() // the layout pass is animated}…What is
viewIsAppearing(_:), and why is it a better place for geometry-dependent setup thanviewWillAppearorviewDidLayoutSubviews?final class AgendaViewController: UIViewController { private let tableView = UITableView() private var todayIndexPath = IndexPath(row: 0, section: 0) // wrong: scrolling in viewWillAppear, bounds and traits may be stale override func viewWillAppear(_ animated: Bool) {…Find the bug: after a few visits to the cart screen, a single cart change is logged to analytics several times.
final class CartViewController: UIViewController { override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) NotificationCenter.default.addObserver( self, selector: #selector(cartDidChange), name: .cartDidChange, object: nil) reloadBadge() } @objc private func cartDidChange() { reloadBadge() analytics.log("cart_changed") }}How do you pass data forward to the next view controller, and back to the previous one?
struct Item { var title: String } final class EditViewController: UIViewController { private var item: Item var onSave: ((Item) -> Void)? // back: a callback the parent sets…What is view controller containment, and which calls do you make to add and remove a child controller?
extension UIViewController { func embed(_ child: UIViewController, in container: UIView) { addChild(child) // 1. relationship child.view.translatesAutoresizingMaskIntoConstraints = false container.addSubview(child.view) // 2. view NSLayoutConstraint.activate([…What is the responder chain, and how does
hitTest(_:with:)decide which view receives a touch?// Enlarge a small button's tap area without changing its sizefinal class BigTapButton: UIButton { override func point(inside point: CGPoint, with event: UIEvent?) -> Bool { bounds.insetBy(dx: -12, dy: -12).contains(point) }}…How do gesture recognizers work, and how do you make a single tap wait for a double tap or a pan work alongside a scroll view?
final class CardViewController: UIViewController, UIGestureRecognizerDelegate { private let scrollView = UIScrollView() private let card = UIView() private var dragStart: CGPoint = .zero override func viewDidLoad() { super.viewDidLoad()…What is the difference between
UIViewandCALayer, and when do you work with a layer directly?final class GradientView: UIView { // The backing layer itself is a gradient: no frame syncing needed override class var layerClass: AnyClass { CAGradientLayer.self } private var gradient: CAGradientLayer { layer as! CAGradientLayer } override init(frame: CGRect) {…What is the difference between
setNeedsLayoutandsetNeedsDisplay, and when doesdraw(_:)run?final class ProgressRingView: UIView { var progress: CGFloat = 0 { didSet { setNeedsDisplay() } // content changed: redraw once } override init(frame: CGRect) {…How does the main run loop work, and why does a
Timerstop firing while the user scrolls?// wrong: scheduledTimer registers for .default only, so it pauses while scrolling// Timer.scheduledTimer(withTimeInterval: 1, repeats: true) { _ in ... } // right: register for .common, which includes .tracking// tick() is a method of the owning controllerlet countdown = Timer(timeInterval: 1, repeats: true) { [weak self] _ in…This controller is dismissed 3 seconds after it opens. What prints, when, and is this a memory leak?
final class DetailViewController: UIViewController { private let statusLabel = UILabel() override func viewDidLoad() { super.viewDidLoad() DispatchQueue.main.asyncAfter(deadline: .now() + 5) { self.statusLabel.text = "Loaded" print("closure ran") } } deinit { print("deinit") }}Find the bug: while the user scrolls fast, rows briefly show another user's avatar, and sometimes the wrong one stays.
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: "Avatar", for: indexPath) as! AvatarCell let user = users[indexPath.row] cell.nameLabel.text = user.name Task { let image = await imageLoader.image(for: user.avatarURL) cell.avatarView.image = image } return cell}