agentsclimarketplace

Memory

Skill rshankras/claude-code-apple-skills/skills/swift/memory

Claude Code skills for Apple platform development (iOS, macOS, iPadOS) — product validation, code generation, App Store optimization, and more

Install
npx -y skills add rshankras/claude-code-apple-skills --skill memory

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

What its author says it does

Copied from the file, not written here

Swift 6.2 InlineArray and Span types for zero-overhead memory access, fixed-size collections, and safe pointer alternatives. Use when optimizing performance-critical code paths.

SKILL.md

13.0 KB, as published. Nobody here has run it

InlineArray and Span

Guidance for Swift 6.2's low-level memory types: InlineArray for fixed-size inline storage without heap allocation, and Span for safe, zero-cost access to contiguous memory. These replace common uses of UnsafeBufferPointer and hand-tuned tuple storage with compiler-checked alternatives.

When This Skill Activates

Use this skill when the user:

  • Asks about InlineArray, fixed-size arrays, or stack-allocated collections
  • Mentions Span, MutableSpan, RawSpan, or UTF8Span
  • Wants to eliminate heap allocations in hot paths
  • Is replacing UnsafeBufferPointer or UnsafePointer with safe alternatives
  • Asks about value generics or let count: Int generic parameters
  • Needs zero-copy access to collection storage
  • Mentions inline storage, contiguous memory, or memory layout
  • Is doing binary parsing, signal processing, or embedded Swift work
  • Wants to avoid copy-on-write overhead for small fixed collections
  • Asks about non-escapable types or lifetime dependencies in Swift

Decision Tree

What memory optimization do you need?
│
├─ A fixed-size collection that never grows/shrinks
│  │
│  ├─ Size known at compile time, stored on stack
│  │  └─ InlineArray<N, Element>
│  │     ├─ No heap allocation
│  │     ├─ No reference counting
│  │     └─ No copy-on-write (eager copies)
│  │
│  └─ Size may vary at runtime
│     └─ Array<Element> (standard library)
│
├─ Safe read access to contiguous memory
│  │
│  ├─ Read-only access to typed elements
│  │  └─ Span<Element>
│  │
│  ├─ Mutable access to typed elements
│  │  └─ MutableSpan<Element>
│  │
│  ├─ Read-only access to raw bytes
│  │  └─ RawSpan
│  │
│  ├─ Mutable access to raw bytes
│  │  └─ MutableRawSpan
│  │
│  ├─ Unicode text processing
│  │  └─ UTF8Span
│  │
│  └─ Initializing a new collection's storage
│     └─ OutputSpan
│
├─ Unsafe pointer access (legacy or interop)
│  └─ UnsafeBufferPointer / UnsafeMutableBufferPointer
│     └─ Prefer Span instead for new code
│
└─ Standard dynamic collection
   └─ Array<Element>
      ├─ Heap-allocated, copy-on-write
      └─ Grows/shrinks dynamically

API Availability

APIMinimum VersionNotes
InlineArray<let count: Int, Element>Swift 6.2Uses value generics; @frozen struct
Span<Element>Swift 6.2Non-escapable, lifetime-dependent
MutableSpan<Element>Swift 6.2Mutable variant of Span
RawSpanSwift 6.2Untyped byte-level access
MutableRawSpanSwift 6.2Mutable untyped byte access
UTF8SpanSwift 6.2Unicode-aware text processing
OutputSpanSwift 6.2For initializing collection storage
.span property on Array / ArraySlice / InlineArraySwift 6.2Returns Span<Element>
.bytes property on DataSwift 6.2Returns RawSpan (byte-level access)
[N of T] sugar, InlineArray(repeating:), closure initSwift 6.4[256 of Int] as a type; InlineArray { i in … } (WWDC26 262)
UniqueArray / UniqueBox / Ref / MutableRefSwift 6.4Noncopyable containers + single-value spans — see swift-performance.md

Top 5 Mistakes

#MistakeFix
1Trying to append/remove elements on InlineArrayInlineArray is fixed-size; use Array if you need dynamic sizing
2Returning a Span from a functionSpan is non-escapable and cannot outlive its source; restructure to process data within the same scope
3Capturing a Span in a closureSpan cannot be captured; pass the span as a parameter or use Array for escaped contexts
4Using InlineArray for large or frequently copied collectionsInlineArray copies eagerly (no COW); use Array for large data that is shared or copied often
5Accessing a Span after mutating the source containerMutation invalidates the span; re-acquire the span after any modification

InlineArray

Declaration

@frozen struct InlineArray<let count: Int, Element> where Element: ~Copyable

Initialization

// Explicit count
let a: InlineArray<4, Int> = [1, 2, 4, 8]

// Count inferred from literal
let b: InlineArray<_, Int> = [1, 2, 4, 8]  // count = 4

// Element type inferred from literal
let c: InlineArray<4, _> = [1, 2, 4, 8]    // Element = Int

// Both inferred
let d: InlineArray = [1, 2, 4, 8]           // InlineArray<4, Int>

Memory Layout

Elements are stored contiguously with no overhead. Size equals count * MemoryLayout<Element>.stride:

MemoryLayout<InlineArray<0, UInt16>>.size       // 0
MemoryLayout<InlineArray<0, UInt16>>.stride      // 1
MemoryLayout<InlineArray<3, UInt16>>.size        // 6  (2 bytes x 3)
MemoryLayout<InlineArray<3, UInt16>>.stride       // 6
MemoryLayout<InlineArray<3, UInt16>>.alignment   // 2  (same as UInt16)

Basic Usage

var array: InlineArray<3, Int> = [1, 2, 3]

// Subscript access
array[0] = 4

// Iterate via indices
for i in array.indices {
    print(array[i])
}

// Copies are eager (no copy-on-write)
var copy = array
copy[0] = 99
// array[0] is still 4

InlineArray vs Array

CharacteristicInlineArrayArray
StorageInline (stack or enclosing type)Heap-allocated buffer
SizeFixed at compile timeDynamic
Copy semanticsEager (full copy)Copy-on-write
Reference countingNoneYes (buffer reference)
Exclusivity checksNoneYes
Append/removeNot supportedSupported

Span Family

Span (Read-Only)

Provides safe, direct access to contiguous typed memory. Non-escapable -- cannot outlive the source.

let array = [1, 2, 3, 4]
let span = array.span  // Span<Int>

// Access elements
let first = span[0]
let count = span.count

// Iterate
for element in span {
    print(element)
}

MutableSpan

Mutable access to contiguous storage:

var array = [1, 2, 3, 4]
array.withMutableSpan { span in
    for i in span.indices {
        span[i] *= 2
    }
}
// array is now [2, 4, 6, 8]

RawSpan

Untyped byte-level access for binary data:

let data = Data([0xFF, 0x00, 0xAB, 0xCD])
let rawSpan = data.bytes  // RawSpan over the bytes
let value = rawSpan.unsafeLoadUnaligned(as: UInt8.self)  // loading integers is safe

For writing into uninitialized memory, OutputRawSpan builds a Data incrementally with no manual offset tracking (WWDC25 312):

let output = Data(rawCapacity: totalBytes) { outputSpan in
    // append bytes; outputSpan.count tracks what's been written
}

For binary parsers, Apple ships the open-source swift-binary-parsing library (ParserSpan, overflow-safe parsing initializers by signedness/bit-width/byte-order, validating parsers for RawRepresentable) — already used inside Apple (WWDC25 312).

UTF8Span

Specialized for safe and efficient Unicode processing of UTF-8 encoded text.

Safety Constraints

Non-Escapable: Cannot Return from Functions

Span has a lifetime dependency on the container it was derived from. It cannot be returned:

// ❌ Wrong -- Span cannot escape the function
func getSpan() -> Span<UInt8> {
    let array: [UInt8] = Array(repeating: 0, count: 128)
    return array.span  // Compiler error
}

// ✅ Right -- process within the same scope
func processData(_ array: [UInt8]) {
    let span = array.span
    // Use span here
    let sum = span.reduce(0, +)
}

Invalidation on Mutation

Modifying the source container invalidates any existing span:

// ❌ Wrong -- span is invalidated after mutation
var array = [1, 2, 3]
let span = array.span
array.append(4)        // Invalidates span
// let x = span[0]     // Undefined behavior

// ✅ Right -- re-acquire span after mutation
var array = [1, 2, 3]
array.append(4)
let span = array.span  // Fresh span after mutation
let x = span[0]        // Safe

Performance Considerations

When InlineArray Wins

  • Small, fixed-size data (e.g., color components, matrix rows, coordinate tuples)
  • Hot loops where heap allocation / ARC overhead is measurable
  • Embedded Swift or contexts with no allocator
  • Struct fields that should be stored inline rather than behind a pointer

When Array Wins

  • Collection size is unknown or variable
  • Collection is large and frequently shared (COW avoids full copies)
  • Collection is passed across module boundaries where dynamic sizing is needed

When Span Wins Over UnsafePointer

  • All new code that needs contiguous memory access -- Span provides the same performance with compile-time safety
  • Binary parsing where you read structured data from a byte buffer
  • Algorithm implementations that operate on slices of memory

When UnsafePointer Is Still Needed

  • C interop requiring raw pointer parameters
  • Legacy APIs that predate Span adoption
  • Interfacing with system calls that take pointer arguments

When to Use / When NOT to Use

Use InlineArray When

  • You know the exact element count at compile time
  • You need zero heap allocation (stack storage)
  • The collection is small (< ~64 elements as a guideline)
  • You modify in place but rarely copy the whole collection
  • You are writing performance-critical or embedded code

Do NOT Use InlineArray When

  • The collection size varies at runtime
  • The collection is large and frequently copied (no COW means expensive copies)
  • You need to append, insert, or remove elements
  • You benefit from sharing storage across variables

Use Span When

  • You need fast, safe, read-only access to contiguous memory
  • You want to replace UnsafeBufferPointer with a safe alternative
  • You are processing data in place without needing to escape the reference
  • You are implementing high-performance algorithms on collection storage

Do NOT Use Span When

  • You need to store the reference for later use (Span is non-escapable)
  • You need to pass memory access across async boundaries
  • You need mutable access (use MutableSpan instead)
  • C interop requires actual UnsafePointer arguments

Review Checklist

InlineArray

  • Count is a compile-time constant (value generic), not a runtime variable
  • Collection size is genuinely fixed and will not need dynamic resizing
  • No code attempts to append, insert, or remove elements
  • Copies are intentional -- each assignment copies all elements eagerly
  • Large InlineArray values are not copied in hot loops (pass by inout or reference)
  • MemoryLayout is verified if precise byte layout matters (e.g., GPU buffers, file formats)

Span

  • Span is never returned from a function or stored in a property
  • Span is never captured in an escaping closure
  • Source container is not mutated while a span is in use
  • Span is re-acquired after any mutation to the source
  • Correct span variant is used: Span (read), MutableSpan (write), RawSpan (bytes)
  • UnsafeBufferPointer is only used where C interop requires it; prefer Span otherwise

General Performance

  • Profile before optimizing -- confirm heap allocation or ARC is the actual bottleneck
  • Small fixed collections use InlineArray instead of Array in measured hot paths
  • Span is used instead of UnsafeBufferPointer for safe contiguous access
  • No premature optimization -- Array is correct default for most code

What the payoff can look like when profiling confirms the bottleneck — Apple's QOI-parser case study (WWDC25 312): preallocating one buffer instead of ~1M transient arrays cut execution time over 50%; adopting InlineArray + RawSpan/OutputRawSpan made it another 6× faster by eliminating all retain/release traffic. See swift-performance.md for the full cost model (calls, copying, generics/existentials, closures, noncopyable ownership) and the profiling-symptom table.

References

Keep looking

Skills are one crate of 328,083. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.