Why "print" is Not a Method, But a Crime Against Time
\nLet's be honest: each of us has written print("this_will_never_be_reached") at least once in our lives, hoping it would work. Sometimes — it did. But in serious projects, this approach turns code into a Christmas tree with garlands of logs. Debugging Swift is an art, and today we'll break it down from start to finish. You'll learn how to stop guessing and start debugging iOS applications professionally.
This article is for those who write in Swift but feel that Xcode can do more. We won't teach you the basics — we'll show you how debugging Swift code can be fast, efficient, and even fun. Let's go!
\n\n1. Conditional Breakpoints: Your Personal Detective
\nA regular breakpoint stops execution every time it reaches a line. But what if a bug only appears on the 1000th function call? Or only when userId == 42? That's where conditional breakpoints in Swift come to the rescue.
Right-click on a breakpoint → select "Edit Breakpoint" → enter the condition.
\n\nExample: Catching a Bug in a Loop
\nfor index in 0..<items.count {\n processItem(items[index]) // Bug at index == 5\n}\nPlace a breakpoint on the processItem line and enter the condition: index == 5. Now the debugger will stop exactly where needed. No unnecessary F6 presses.
Action Blocks: Making Breakpoints Smarter
\nIn the same editing window, there's an "Add Action" button. You can:
\n- \n
- Execute
po variableName(print object) — automatically prints the variable's value. \n - Play a sound (yes, really!) — useful when debugging in the background. \n
- Log a message to the console — without stopping execution. \n
Check the "Automatically continue after evaluating" box — and you'll get a super-logger that doesn't slow down your app.
\n\n2. LLDB: The Console That Can Do Everything
\nMany developers ignore the debug console, thinking it only has po and p. In reality, LLDB (Low Level Debugger) is the Swiss Army knife of Swift debugging. Here are 5 commands that will change your life:
- \n
po— prints an object by callingdescriptionordebugDescription. Ideal for UIKit objects. \n p— prints a value without callingdescription. Useful for primitives. \n v— shows variables in the current frame. Faster than looking at the Variables panel. \n expression— executes any Swift code right during a pause. Want to change a variable's value?expression self.title = "New Title". \n thread backtrace— shows the call stack. If the app crashes, this is the first thing to do. \n
Live Example: Changing the UI on the Fly
\nImagine: you've stopped at a breakpoint in viewDidLoad. In the console, type:
expression self.view.backgroundColor = .red\nexpression self.view.layoutIfNeeded()\nAnd voila! The simulator screen instantly turns red. This way, you can test animations, colors, and texts without restarting.
\n\n3. View Debugging: Peeking Under the UI Hood
\nA layout bug is a classic. The button is not where it should be, the label overlaps the image, or constraints behave like guerrillas. View Debugging in Xcode is an X-ray for your interface.
\nClick the "Debug View Hierarchy" button (it looks like three squares) in the bottom panel. You'll see a 3D scene of all UI elements. You can rotate, zoom, highlight constraints, and see their numerical values.
\n\nTechnique: "Catch the Constraint"
\nIf an element is not in its place, select it in the 3D scene and look at the list of constraints. Red lines indicate conflicting ones, ye