“Listen: David Smith has come unstuck in time.” — Kurt Vonnegut, probably

Cohost bonus feature: 80% less professional

posts from @Catfish-Man tagged #objective c

also:

If you write code in C, C++, Objective-C, Swift, Rust (I think?), and probably some other languages, and you don't already regularly use ASAN (Address Sanitizer) and TSAN (Thread Sanitizer), you may be entitled to compensation are probably1 way more frustrated than necessary. I can't count the number of times I've gone from "this bug is impossible, it reproduces once every 10,000 attempts and makes no sense" to "oh there's the problem" just by clicking a checkbox and recompiling.


  1. or you're working in an unusual environment or have unusual needs



Consider the following trivial test program

import Foundation

func test(_ str: String) {
    let count = 10_000_000
    let start = Date()
    for _ in 0 ... count {
        _ = str as NSString
    }
    let elapsed = -(start.timeIntervalSinceNow)
    print("\(elapsed) seconds to bridge \(str.count) 'a's \(count) times")
}

for str in (0 ... 20).map({ String(repeating: "a", count: $0) }) {
    test(str)
}

Would you expect it to output this? (unnecessary extra precision elided for clarity)

0.12 seconds to bridge 0 'a's 10000000 times
0.11 seconds to bridge 1 'a's 10000000 times
0.12 seconds to bridge 2 'a's 10000000 times
0.13 seconds to bridge 3 'a's 10000000 times
0.13 seconds to bridge 4 'a's 10000000 times
0.14 seconds to bridge 5 'a's 10000000 times
0.14 seconds to bridge 6 'a's 10000000 times
0.15 seconds to bridge 7 'a's 10000000 times
0.13 seconds to bridge 8 'a's 10000000 times
0.13 seconds to bridge 9 'a's 10000000 times
0.13 seconds to bridge 10 'a's 10000000 times
0.14 seconds to bridge 11 'a's 10000000 times
0.74 seconds to bridge 12 'a's 10000000 times
0.74 seconds to bridge 13 'a's 10000000 times
0.74 seconds to bridge 14 'a's 10000000 times
0.73 seconds to bridge 15 'a's 10000000 times
0.10 seconds to bridge 16 'a's 10000000 times
0.10 seconds to bridge 17 'a's 10000000 times
0.10 seconds to bridge 18 'a's 10000000 times
0.10 seconds to bridge 19 'a's 10000000 times
0.10 seconds to bridge 20 'a's 10000000 times

Can you figure out why there's a discontinuity between 11 and 12 characters long? (Hint: try logging the actual class of the NSString each time)

How about between 15 and 16? (This one is about differences in the input string rather than the output)



Pet peeve: programmers thinking of weak references as meaning "do it correctly", and sprinkling them in without thinking about the implications

Weak references are relatively scary things to have in your code! In ObjC, your stuff using them might silently just do nothing. In Swift it's less silent (since you have to check the optional), but when I see people advocating for always capturing self weakly, it's clear that they are substituting """best practices""" for thought.

When the optimizer improved to be able to shorten lifetimes fully, TONS of code in the wild broke due to lurking misuse of weak references that had previously coincidentally not bitten them. The compiler team had to redesign the entire value lifetime system to accommodate.

There is no substitute for learning what weak references actually mean and then sitting down and thinking about your object graph. You cannot rule-of-thumb your way out of this.

Related pet peeve: calling everything under the sun a reference cycle. No, capturing self is not necessarily a reference cycle. No, memory leaks are not reference cycles. No, strong captures are not necessarily reference cycles. No, DispatchQueue.async cannot ever cause a reference cycle. Neither can DispatchQueue.sync. No, your random bug is probably not caused by a reference cycle. No, your crash is almost definitely not caused by a reference cycle (unless it's crashing due to running out of memory, then maybe).