BS
BleepingSwift
Published on

> Understanding the "some" Keyword in Swift and SwiftUI

Authors
  • avatar
    Name
    Mick MacCallum
    Twitter
    @0x7fs

If you've written any SwiftUI code, you've seen some View everywhere. That some keyword might seem mysterious at first, but it solves a real problem in Swift's type system. Understanding it will help you write better SwiftUI code and make sense of compiler errors when they appear.

The Problem some Solves

Swift is a strongly typed language. Every function needs to declare what type it returns. Consider a function that returns a View:

func makeGreeting() -> Text {
    Text("Hello, World!")
}

This works fine because Text is a concrete type. But what if you want to add a modifier?

func makeGreeting() -> ??? {
    Text("Hello, World!")
        .padding()
        .background(Color.blue)
}

What's the return type? It's actually something like ModifiedContent<ModifiedContent<Text, _PaddingLayout>, _BackgroundStyleModifier<Color>>. These nested generic types quickly become unmanageable, and some of them are private implementation details you can't even reference.

Opaque Return Types

The some keyword creates an opaque return type. It tells the compiler "this function returns a specific concrete type that conforms to this protocol, but I don't want to spell out exactly what that type is."

func makeGreeting() -> some View {
    Text("Hello, World!")
        .padding()
        .background(Color.blue)
}

The compiler knows exactly what type is being returned—it just doesn't expose that information to the caller. This is different from returning a protocol type directly:

// This returns "some concrete type conforming to View"
func makeView() -> some View {
    Text("Hello")
}

// This returns "any type conforming to View" (existential)
func makeView() -> any View {
    Text("Hello")
}

The difference matters for performance and type safety. With some, the compiler knows the exact type at compile time and can optimize accordingly. With any, the type is boxed in an existential container with runtime overhead.

Why SwiftUI Requires some View

SwiftUI's View protocol has an associated type called Body:

protocol View {
    associatedtype Body: View
    var body: Self.Body { get }
}

Protocols with associated types can't be used directly as return types without some or any. When you write var body: some View, you're telling Swift that body returns a specific view type that the compiler can figure out from the implementation.

Consistency Matters

Opaque return types require consistency. This code won't compile:

func makeView(showTitle: Bool) -> some View {
    if showTitle {
        return Text("Title")  // Returns Text
    } else {
        return Image(systemName: "star")  // Returns Image
    }
}

Both branches return different types, but some View promises a single concrete type. The fix is to use a type-erasing container or a conditional modifier:

// Option 1: Use @ViewBuilder
@ViewBuilder
func makeView(showTitle: Bool) -> some View {
    if showTitle {
        Text("Title")
    } else {
        Image(systemName: "star")
    }
}

// Option 2: Wrap in Group
func makeView(showTitle: Bool) -> some View {
    Group {
        if showTitle {
            Text("Title")
        } else {
            Image(systemName: "star")
        }
    }
}

The @ViewBuilder attribute enables SwiftUI's result builder syntax, which automatically wraps conditional views in the appropriate container type.

some vs any

Swift 5.7 introduced any for existential types, making the distinction clearer:

// Opaque type - compiler knows the concrete type
func makeSomeView() -> some View {
    Text("Hello")
}

// Existential type - type is erased at runtime
func makeAnyView() -> any View {
    Text("Hello")
}

Use some when you can—it's more efficient and enables better type checking. Use any when you need to store heterogeneous types or when the concrete type genuinely varies at runtime.

Primary Associated Types

Swift 5.7 also introduced primary associated types, which you'll see with collections:

func numbers() -> some Collection<Int> {
    [1, 2, 3, 4, 5]
}

This returns "some collection of integers" without specifying whether it's an Array, Set, or other collection type. The caller knows it's a collection of Int values, which is often all they need.

When You'll See Compiler Errors

Common situations where the some keyword causes confusion:

If you forget some, you'll see an error about protocols with associated types:

// Error: Protocol 'View' can only be used as a generic constraint
var body: View {
    Text("Hello")
}

If you return different types from branches:

// Error: Function declares an opaque return type, but the return statements
// in its body do not have matching underlying types

If you try to store an opaque type in a variable without type inference:

// This works - type is inferred
let view = makeGreeting()

// This doesn't work - can't use 'some' for stored properties
let view: some View = makeGreeting()  // Only works in certain contexts

Practical Usage

In day-to-day SwiftUI development, you'll mostly use some View for your view body properties and helper methods that return views. The type system handles the complexity behind the scenes:

struct ProfileCard: View {
    let name: String
    let title: String

    var body: some View {
        VStack(alignment: .leading) {
            headerSection
            Divider()
            detailsSection
        }
        .padding()
        .background(.regularMaterial)
        .cornerRadius(12)
    }

    private var headerSection: some View {
        Text(name)
            .font(.headline)
    }

    private var detailsSection: some View {
        Text(title)
            .font(.subheadline)
            .foregroundStyle(.secondary)
    }
}

Each computed property returns some View, keeping the actual types hidden while still being fully type-safe. The compiler ensures everything fits together correctly, and you don't have to think about the nested generic types being created.

subscribe.sh

// Stay Updated

Get notified when I publish new tutorials on Swift, SwiftUI, and iOS development. No spam, unsubscribe anytime.

>

By subscribing, you agree to our Privacy Policy.