Home


Hack to understand ‘some’ better

When I see it in code, read it as ‘particular’ instead of ‘some’.

‘any’ is an existential. Relies on dynamic dispatch.

‘some’ is an opaque type to the caller, but still has identity that the compiler knows of.

Easiest to think of as ‘reverse generics’:

"An opaque return type can be thought of as putting the generic signature "to the right" of the  
function arrow; instead of being a type chosen by the caller that the callee sees as  
abstracted, the return type is chosen by the callee, and comes back to the caller as  
abstracted"  

Soruce: https://github.com/swiftlang/swift-evolution/blob/main/proposals/0244-opaque-result-types.md

Swift Customization Point

protocol X {
var y: String // this is a customization point
}

extension X {
var z: String {
“Not a customization point!”
}

// default implementation  
var y: String {  
    "hello world"  
}  

}

// X#z can’t be customized, but X#y can

How to propagate task cancellation to an asyncstream

https://forums.swift.org/t/why-asyncstream-breaks-structured-concurrency/71477/4

Swift gotcha: A Task does not create a child task.
https://forums.swift.org/t/why-asyncstream-breaks-structured-concurrency/71477/3
Read all answers by robert.ryan in that thread

Visual on different ways to create a task:
https://forums.swift.org/t/should-task-groups-inherit-actor/57547/2

Can use compiler version as proxy for base sdk version

Handy when trying to conditionally compile a lib feature that is backdeployed
but not available for customers on older versions of Xcode:

https://forums.swift.org/t/conditionally-compile-based-on-ios-version-previewcgimagerepresentation-broke/50883/2

The case for allowing force unwraps in prod code

Quinn the Eskimo: https://forums.swift.org/t/how-to-handle-errors-in-swift-when-coming-from-a-java-world/20821/13

Swift dictionaries are value types, but not immutable

struct S {  
    var x = 1  
}  

var y: [String: S] = ["a": S()]  
y["a"]?.x = 2  
y["a"]?.x  // Returns 2!  

I figured I would have to do this:

var y: [String: S] = ["a": S()]  
y["a"] = S(x: 2)  

The first snippet rewritten with an assignment does what I expect:

struct S {  
    var x = 1  
}  

var y: [String: S] = ["a": S()]  
var z = y["a"]  
z?.x = 2  
y["a"]?.x  // Returns 1  

Returning to first snippet. Will didSet handlers get called with this setup:

struct S {  
    var x = 1  
}  

final class C {  
    var y: [String: S] = ["a": S()] {  
        didSet {  
            print("Am I called?")  
        }  
    }  
    func mutate() {  
        self.y["a"]?.x = 2  
    }  
}  

C().mutate()  
// Prints "Am I called?"  

Swift concurrency nonisolated

“Marking something as nonisolated tells the compiler that you’re not going to touch any of the
isolated state and therefore this function can be called from anywhere”
https://developer.apple.com/videos/play/wwdc2021/10194/?time=2302

Swift concurrency what happens at suspension point

Quinn the Eskimo!

In Swift concurrency, tasks are run by threads from the Swift concurrency cooperative thread  
pool. When a task suspends at an await, the thread running that task returns to the thread pool  
and looks for more work to do.  

https://developer.apple.com/forums/thread/708182

Swift concurrency equivalent of dispatching async to the main queue in gcd

Another Quinn the Eskimo! gem: https://developer.apple.com/forums/thread/760725

actor MyActor {  
    func doStuff() {  
        Task { @MainActor in  
            MainActorState.counter += 1  
        }  
    }  
}  

Also notice how he annotates the static var below as @MainActor. You can’t apply that
annotation to the enclosing type:

enum MainActorState {  
    @MainActor static var counter: Int = 0  
}  

actor MyActor {  

    func doStuff() {  
        MainActorState.counter += 1  
                    // ^ Main actor-isolated static property 'counter' can not  
                    // be mutated on a non-isolated actor instance  
    }  
}  

Swift gotcha: actors do not isolate static properties and methods

This does not isolate doSomething:

@globalActor public actor RealtimeActor {  
    public static let shared = RealtimeActor()  
}  

@RealtimeActor  
final class Foo {  
    static func doSomething() {}  
}  

Try it in a sample project. You can call Foo.doSomething outside of a task, and it will
execute on the main thread.

Parallel async and join

https://x.com/nsobject/status/1892611473144213584

For functions that return void:

let d = Date()  
async let parallelDep1: Void = wait1()  
async let parallelDep2: Void = wait2()  
_ = await (parallelDep1, parallelDep2)  
print(String(format: "Deps loaded in %.2f seconds", Date().timeIntervalSince(d)))  

private func wait1() async {  
    try? await Task.sleep(for: .seconds(1))  
}  

private func wait2() async {  
    try? await Task.sleep(for: .seconds(1))  
}  

Pause and signal

Quinn the Eskimo! says:

My favourite trick for this problem in general is to add a pause() system call to the front of  
my code. That stops the process until it receives a signal, and the act of attaching the  
debugger generates that signal and thus you can just continue from there.  

https://forums.swift.org/t/editing-and-debugging-a-swiftpm-plugin/71935/6

How to write an async getter

private static var myString: String {  
    get async {  
        return await getTheString()  
    }  
}  

How to sleep

try? await Task.sleep(nanoseconds: 1_000_000_000)  

How to perform an action after delay

DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(2)) {  
    print("hello")  
}  

// or  

Task {  
    try? await Task.sleep(nanoseconds: 2_000_000_000)  
    print("world")  
}  

AI can’t understand customization points

AI bad at POP. When to use customization points vs default extensions.
It can tell you what they are, but it won’t design w/ them. Yet.

How to inspect SPM package

From root of package:

swift package dump-package  

How to check if a task was canceled

From within the task:

try Task.checkCancellation()  

How to use an enum with associated value outside of switch

if case let .longHTTP(wait: wait) = strategy {  
    request.addValue("Prefer", forHTTPHeaderField: "wait=\(wait)")  
}  

How to deserialize without Decodable

First, use Decodable. But if I’m roughing something in:

import Foundation  
let myData: Data = ...  
let deserialized = try JSONSerialization.jsonObject(with: myData)  
guard let json = deserialized as? [String: Any] else {  
    throw MyError("Could not deserialize data to [String: Any]")  
}  

How to catch Foundation URLError:

URLRequest comes with a default timeout of 60 seconds. Can catch timeouts with (see line 27):
https://gist.github.com/lzell/42b47aa5e521a3e20840aba093a7c835

Why not use snake case option in decodable everywhere?

It fails for properties that I have setup with acronyms, e.g. 

struct Response: Decodable {  
    let fooURL // I want this to map to "foo_url"  
}  

JSONDecoder throw encountering unescaped newline

The error:

"Unescaped control character '0xa' around line 3, column 0."  

is due to an unescaped newline in a JSON field. Repro:

let response = """  
{  
  "message": "will\nfail"  
}  
"""  

struct Response: Decodable {  
    let message: String  
}  

_ = try! JSONDecoder().decode(Response.self, from: response.data(using: .utf8)!)  

How to modify localizedDescription on an error

It’s actually Foundation that adds the localizedDescription property on an error. For example,
this fails in a repl:

enum MyError: Error {  
    case foo  
}  
do {  
    throw MyError.foo  
} catch {  
    print(error.localizedDescription)  
}  

but if I import Foundation first, it works as expected.

To modify the error description, use this:

import Foundation   
   
enum MyError: LocalizedError {    
    case foo    

    var errorDescription: String? {    
        switch self {    
        case .foo:    
            return "My description"    
        }    
    }    
}    
   
do {    
    throw MyError.foo    
} catch {    
    print(error.localizedDescription) // prints 'My description'  
}  

Swift Foundation URL

URLComponents are not needed to get out the domain and path.

let url = URL(string: "https://api.aiproxy.pro/foo/bar")!  

Get the domain

url.host  

Get the path

url.path  

Swift errors versus exceptions

Error handling in Swift resembles exception handling in other languages, with the use of the  
try, catch and throw keywords. Unlike exception handling in many languages — including  
Objective-C — error handling in Swift doesn’t involve unwinding the call stack, a process that  
can be computationally expensive. As such, the performance characteristics of a throw statement  
are comparable to those of a return statement.  

From: https://docs.swift.org/swift-book/documentation/the-swift-programming-language/errorhandling/

Pattern to split nested types out into their own files

// A.swift  
struct A {  
}  

// A+B.swift  
extension A {  
    struct B {  
    }  
}  

I think it’s more common to use this pattern for protocol conformance, but I like it for nested
structs too. I searched around for examples of Apple code that uses this pattern. It’s in
swift-foundation:

https://developer.apple.com/documentation/foundation/date/iso8601formatstyle
https://github.com/apple/swift-foundation/blob/main/Sources/FoundationEssentials/Formatting/Date%2BISO8601FormatStyle.swift#L24

How to use a generic constraint

f and g are equivalent here:

protocol P {}  

struct S: P {}  

func f<T>(_ t: T) where T: P {}  

func g<T: P>(_ t: T) {}  

f(S())  
g(S())  

Apple calls the first syntax a ‘generic where clause’ and the second a ‘generic parameter
clause’. The only different, as far as I can tell, is the where clause can support constraints
on a protocol’s associated types, e.g. where S1.Iterator.Element == S2.Iterator.Element

If I am not working with PATs, I prefer the syntax func g<T: P>(_ t: T)

How to conditionally add extensions to generic types

struct S<T> {  
    let s: T  
}  

extension S where T == Int {  
    func plusOne() -> Int {  
        return self.s + 1  
    }  
}  

let x = S<Int>(s: 1)  
print(x.plusOne())  // prints 2  

Syntax to create a string that contains double quotes

Instead of

"{\"x\":\"y\"}"  

Use

#"{"x":"y"}"#  

For a multiline string that I don’t want to escape quotes or slashes:

#"""  
This is  
"cool"  
"""#  

Future proof decodables with enums

See the ‘future proof’ section here: https://www.donnywals.com/writing-custom-json-encoding-and-decoding-logic/

Encodable enum with associated value

Always name the associated value, otherwise you get a 0: "whatever" in your encoded json.

JSON encoding with heterogeneous dict

The fact that I need to introduce type erasure for a concept this simple is still wild to me:

let dict = ["A": "x", "B": 2]  
try? JSONEncoder().encode(dict)  // Won't work  

We had this with obj-c out of the box.

Redditor to the rescue: https://www.reddit.com/r/swift/comments/1ecv7dw/wrangling_json_in_swift/

let dict: [String: Any] = ["A": "x", "B": 2]  
let data = try? JSONSerialization.data(withJSONObject: dict)  
String(data: data!, encoding: .utf8)  

How to achieve a sum type

Swift doesn’t have a sum or union. What do people use instead? Enum with associated values

How to concatenate Data

Use the + overload:

Data() + Data()  

How to generate a UUID

import Foundation  
UUID().uuidString  

How to use FatalError versus throwing Errors

Swift closure with named argument

[1,2,3].map { x in x + 1 }  

Swift closure with unnamed argument

[1,2,3].map { $0 + 1 }  

Swift make command line tool run forever

RunLoop.current.run()  

Swift Encodable, Decodable, Codable

Codable is defined as

public typealias Codable = Decodable & Encodable  

If I only want to create types that are encodable, use struct MyMessage: Encodable

Swift Encodable example, to json

import Foundation  

struct S: Encodable {  
    let x: String  
    let y: Int  
}  

let s = S(x: "hello", y: 123)  
let jsonData = JSONEncoder().encode(s)  
if let jsonStr = String(data: jsonData, encoding: .utf8) {  
    print(jsonStr)  
    // prints {"x":"hello","y":123}  
}  

Writing unit tests against encodable structs

There is no guarantee of key order when structs are encoded. For unit tests,
create the encoder with the following for predictable serialization results:

let encoder = JSONEncoder()  
encoder.outputFormatting = .sortedKeys  

Swift concurrency beginner’s error

Don’t put Tasks everywhere. Try to stay structured

(swift, stringify without using codable)

private func stringify(_ args: [String: Any]) -> Data? {  
    if JSONSerialization.isValidJSONObject(args) {  
        return try? JSONSerialization.data(withJSONObject: args, options: [])  
    }  
    return nil  
}  

(swift, remove from dictionary)

var x = ["a": 1]  
x.removeValue(forKey: "a")  
x #=> [:]  

(swift, tuple destructuring)

 var x = (1, "hello")  
 var (a, b) = x  
 a #=> 1  
 b #=> "hello"  

(swift, special case for simulator)

#if targetEnvironment(simulator)  
    // Do something special  
#endif  

How to conditionally compile for macOS

#if os(macOS)  
print("mac")  
#else  
print("not mac")  
#endif  

(swift, dictionary, increment key, ruby ||=)
var x = String: Int
x[“a”, default: 0] += 1 // a maps to 1
x[“a”, default: 0] += 1 // a maps to 2

(swift async streams, continuations)
- AsyncStream conforms to AsyncSequence
- See the docstring on AsyncThrowingStream for modifying an existing
closure-based callback earthquake monitor into an async/await-compatible interface
- See continuation reference in wwdc/modern_crash_course_takeaways.txt
- Sendable is “A type whose values can safely be passed across concurrency domains by copying.”
- See ~/dev/ContinuationExperiment

(swift get type of instance)
type(of: myInstance)

(swift regex, repl)
Start the repl with:

swift repl -enable-bare-slash-regex  
> var a = "a"  
> let re = /a/  
> a.replace(re) { match -> String in "b" }  
> a  
// Outputs "b"  

What most languages call ‘lazy’ (i.e. ? after a pattern), swift calls ‘reluctant’:
See Swift Regex: Beyond the basics, 12:35

(swift regex, SPM)
Modify the target sections of Package.swift to look like this:

.target(  
    name: "AIProxySwift",  
    swiftSettings: [  
        .unsafeFlags(["-Xfrontend", "-enable-bare-slash-regex"])  
    ]  
),  
.testTarget(  
    name: "AIProxySwiftTests",  
    dependencies: ["AIProxySwift"],  
    swiftSettings: [  
        .unsafeFlags(["-Xfrontend", "-enable-bare-slash-regex"])  
    ]  
),  

New questions

How to use globalActor to annotate functions

@globalActor actor MyStickerActor {  
    static let shared = MyStickerActor()  
}  
// Then...  
@MyStickerActor  
func createSticker(_ prompt: String) async throws -> UIImage  

(gcd notes, libdispatch notes, use it right, serial queue)
https://gist.github.com/tclementdev/6af616354912b0347cdf6db159c37057

(swift data)
How to create a model container outside of SwiftUI context:
https://developer.apple.com/documentation/swiftdata/preserving-your-apps-model-data-across-launches

References to organize:
// Meet SwiftData: https://developer.apple.com/videos/play/wwdc2023/10187/
// Build an App with Swift Data: https://developer.apple.com/videos/play/wwdc2023/10154
// https://developer.apple.com/xcode/swiftdata/
// bug: https://developer.apple.com/forums/thread/732788
//
// Swipe to delete: https://developer.apple.com/documentation/swiftdata/deleting-persistent-data-from-your-app
//

(swift, start repl)
swift repl

(swift, string interpolation, concatentation, floats)

// Interpolation
let a = “a”
let a_ = “(a)”
a == a_ # => true

// Concatenation
a + “b” == “ab” # => true

// Printing multiple strings
print(a, “b”) # => prints “a b”

// Printing floats
import Foundation
let a = 1.2345
String(format: “%.2f”, a) # => 1.23

// Separating string variables from the string template:
import Foundation
String(format: “%@ %@”, “hello”, “world”)

(property wrappers)

Minute 27 of “modern swift API design”

(smells, protocol, overuse, protocols aren’t mixins)
Add to my talk: minute 13 of wwdc “modern swift API design”.
If conformer calls protocol definitions, you’re using it wrong.

(swift add convenience initializer to struct, keep memberwise initializer)
Add the initializer in an extension to avoid losing the default memberwise initializer

(swift demangle, stack trace, demangle)
xcrun swift-demangle

(assembly, swift)
For anyone curious how to look at assembly for snippets of swift, this is what
I ran: xcrun -sdk iphoneos swiftc -target arm64-darwin-ios11 -O -S -o - input.swift | xcrun swift-demangle | less

(repl, swift, lookup, type)
$ swift repl
> :type lookup String

Use this to search the api with fuzzy search (ctrl+6 once open):
printf “import Foundation:type lookup String” | swift > /tmp/foo.swift && open -a /Applications/Xcode.app /tmp/foo.swift

(repl, spm, swift, package, import module)
Start repl with:
$ swift build && swift -I.build/debug -L.build/debug -lBluetoothService
> import BluetoothService

(swift compiler, swiftc)
Additional help:
swiftc -help-hidden

(switch swift version)
$ sudo xcode-select -switch /Applications/Xcode-beta.app
$ xcrun swift –version

(swift, get type)
“foo”.dynamicType

(swift, initializers)
http://stackoverflow.com/questions/29956195/idiomatic-pattern-to-initialize-uiviews-in-swift

Will be able to find *-Swift.h in:
~/Library/Developer/Xcode/DerivedData/

Repl

Run with:
xcrun swift
or yosemite:
swift
or:
lldb –repl

When modifying previously entered input: insert newline with opt+enter

Type :help to get list of commands
:quit to quit

To set a breakpoint from within repl, create a function called go, then set a
breakpoint in the body with:
:breakpoint set –line
Then call go()

LLDB - Debugging (script, lldb, swift, debugging, dsym)

Emit debug information:
$ swiftc filename.swift -g
Run program with lldb:
$ lldb -f filename
Set breakpoint:
(lldb) breakpoint set –file filename.swift –line 1
Run:
(lldb) run

Print lots of information:
(lldb) fr v -R

Change the variable to nil:
(lldb) p x = nil
Dump it again:
(lldb) fr v -R x

(lldb) expression -l objc -O – (id) 0xaddressofobject