All skills
Skillintermediate

Swift Sharp Edges

```swift // DANGEROUS: Crashes on nil let value = optionalValue! // Runtime crash if nil

Claude Code Knowledge Pack7/10/2026

Overview

Swift Sharp Edges

Force Unwrapping

// DANGEROUS: Crashes on nil
let value = optionalValue!  // Runtime crash if nil

// Common in:
let cell = tableView.dequeueReusableCell(...)!
let url = URL(string: userInput)!
let data = try! JSONDecoder().decode(...)

// DANGEROUS: Implicitly Unwrapped Optionals
var name: String!  // IUO - crashes if accessed while nil

class ViewController: UIViewController {
    @IBOutlet weak var label: UILabel!  // Nil before viewDidLoad
}

Fix: Use optional binding or nil-coalescing:

if let value = optionalValue {
    use(value)
}
let value = optionalValue ?? defaultValue
guard let value = optionalValue else { return }

try! and try?

// DANGEROUS: try! crashes on error
let data = try! Data(contentsOf: url)

// DANGEROUS: try? silently converts error to nil
let data = try? Data(contentsOf: url)
// No way to know if failure was "file not found" or "permission denied"

// DANGEROUS: Ignoring error completely
do {
    try riskyOperation()
} catch {
    // Error swallowed
}

Fix: Handle errors explicitly:

do {
    let data = try Data(contentsOf: url)
} catch let error as NSError where error.code == NSFileNoSuchFileError {
    // Handle file not found
} catch {
    // Handle other errors
}

as! Force Cast

// DANGEROUS: Crashes if cast fails
let user = object as! User

// Common antipattern:
let cell = tableView.dequeueReusableCell(...) as! CustomCell
// Crashes if wrong identifier or wrong class

Fix: Use conditional cast:

if let user = object as? User {
    use(user)
}
guard let user = object as? User else {
    return  // or handle error
}

String/NSString Bridging

// DANGEROUS: Different indexing semantics
let nsString: NSString = "café"
let swiftString = nsString as String

nsString.length        // 5 (UTF-16 code units)
swiftString.count      // 4 (extended grapheme clusters)

// Range confusion:
let range = nsString.range(of: "é")  // NSRange (UTF-16)
// Can't directly use with String (uses String.Index)

// DANGEROUS: Emoji handling
let emoji = "👨‍👩‍👧‍👦"  // Family emoji
emoji.count           // 1 (grapheme cluster)
emoji.utf16.count     // 11 (UTF-16)
(emoji as NSString).length  // 11

Reference Cycles

// DANGEROUS: Strong reference cycles cause memory leaks
class Person {
    var apartment: Apartment?
}
class Apartment {
    var tenant: Person?  // Strong reference
}

let john = Person()
let apt = Apartment()
john.apartment = apt
apt.tenant = john  // Cycle! Neither deallocated

// DANGEROUS: Closures capture self strongly
class MyClass {
    var callback: (() -> Void)?

    func setup() {
        callback = {
            self.doSomething()  // Strong capture of self
        }
    }
}

Fix: Use weak or unowned:

class Apartment {
    weak var tenant: Person?  // Weak breaks cycle
}

callback = { [weak self] in
    self?.doSomething()
}

Array/Dictionary Thread Safety

// DANGEROUS: Collections are not thread-safe
var array = [Int]()

// Thread 1:
array.append(1)

// Thread 2:
array.append(2)

// Crash or corruption possible!

Fix: Use serial dispatch queue, locks, or actors (Swift 5.5+):

actor SafeStorage {
    private var items = [Int]()

    func add(_ item: Int) {
        items.append(item)
    }
}

Numeric Overflow

// In debug: crashes (overflow check)
// In release: also crashes by default (unlike C)
let x: Int8 = 127
let y = x + 1  // Fatal error: arithmetic overflow

// BUT: If using &+ operators, wraps silently
let y = x &+ 1  // -128 (wrapping)

This is safer than C, but &+ operators can still cause issues.

Uninitialized Properties

// DANGEROUS: Accessing before initialization
class MyClass {
    var value: Int

    init() {
        print(value)  // Compile error in Swift, thankfully
        value = 42
    }
}

// BUT: @objc interop can bypass
// AND: Unsafe pointers have no initialization guarantees

Protocol Witness Table Issues

// DANGEROUS: Protocol with Self requirement
protocol Equatable {
    static func ==(lhs: Self, rhs: Self) -> Bool
}

// Can't use heterogeneously:
var items: [Equatable] = [...]  // Error!
// Must use type erasure or existentials

KeyPath Subscript Confusion

// DANGEROUS: Similar syntax, different behavior
struct User {
    var name: String
    subscript(key: String) -> String? { ... }
}

user["name"]       // Calls subscript
user[keyPath: \\.name]  // Uses KeyPath

// Easy to confuse when debugging

Codable Pitfalls

// DANGEROUS: Decoding fails silently with wrong types
struct User: Codable {
    var id: Int
}

// JSON: {"id": "123"}  // String, not Int
// Throws DecodingError, but often caught broadly

// DANGEROUS: Missing keys
struct User: Codable {
    var id: Int
    var name: String  // Required
}

// JSON: {"id": 1}  // Missing "name"
// Throws, but error message may not be clear

Fix: Use explicit CodingKeys and handle errors:

struct User: Codable {
    var id: Int
    var name: String?  // Optional for missing keys

    enum CodingKeys: String, CodingKey {
        case id
        case name
    }
}

Objective-C Interop

// DANGEROUS: Objective-C returns nullable even when Swift sees non-optional
@objc func legacyMethod() -> NSString  // May actually return nil

// DANGEROUS: Objective-C exceptions not caught by Swift
// NSException bypasses Swift error handling

// DANGEROUS: Objective-C performSelector
let result = obj.perform(NSSelectorFromString(userInput))
// Can call any method!

Detection Patterns

PatternRisk
! force unwrapCrash on nil
as! force castCrash on type mismatch
try!Crash on error
try? without handling nilSilent failure
String! IUO typesDeferred crash
Closure capturing self without [weak self]Memory leak
Collections modified from multiple threadsRace condition
NSString/String conversion with rangesIndex mismatch
&+, &-, &* operatorsSilent overflow
@objc methods returning non-optionalNil bridge issues