CtrlK
BlogDocsLog inGet started
Tessl Logo

dpearson2699/swift-ios-skills

Agent skills for iOS, iPadOS, Swift, SwiftUI, and modern Apple framework development.

90

Quality

90%

Does it follow best practices?

Impact

Average score across 248 eval scenarios

SecuritybySnyk

Advisory

Suggest reviewing before use

Overview
Quality
Evals
Security
Files

predicate-pitfalls.mdskills/swiftdata/references/

#Predicate Pitfalls

Common runtime crashes and build errors when using #Predicate with SwiftData.

Unsupported Expressions

#Predicate compiles Swift expressions into a query representation. Only a subset of Swift is supported. Unsupported expressions compile but crash at runtime.

PatternCrash?Fix
$0.name.uppercased() == "PARIS"Runtime crashUse localizedStandardContains or caseInsensitiveCompare
$0.name.count > 5Runtime crashStore length in a separate property or filter after fetch
$0.tags.count == 0Runtime crashUse $0.tags.isEmpty (iOS 17.4+) or a stored flag
$0.name.isEmpty on optional StringRuntime crash on some OS versionsUse $0.name == nil || $0.name == ""
Custom computed propertyRuntime crashOnly stored @Attribute properties work in predicates
Date.now captured by valueStale predicateCreate a let now = Date() before the predicate and capture it
Enum raw value comparisonRuntime crash (pre-iOS 18)Store the raw value as a separate property, or target iOS 18+
Loops, declarations, mutation, or switch-heavy control flowBuild error or runtime failureUse boolean logic, ternary expressions, optional chaining, or optional binding patterns supported by Foundation Predicate
Arbitrary method callsRuntime crashOnly supported methods (see below) work

Supported Operations

Comparisons: ==, !=, <, <=, >, >=

Logic: &&, ||, !

String: localizedStandardContains(_:), contains(_:), starts(with:), caseInsensitiveCompare(_:)

Collections: contains(where:), allSatisfy(_:), filter(_:), .isEmpty

Other: optional chaining, nil coalescing (??), ternary (? :), arithmetic (+, -, *, /), type casting (as?, is)

Safe Pattern: Build Predicates Dynamically

func tripPredicate(searchText: String, favoritesOnly: Bool) -> Predicate<Trip> {
    let now = Date()
    return #Predicate<Trip> { trip in
        (searchText.isEmpty || trip.destination.localizedStandardContains(searchText))
        && (!favoritesOnly || trip.isFavorite)
        && trip.startDate > now
    }
}

Capture all external values as let bindings outside the predicate closure. The predicate captures them by value at creation time.

Debugging Predicate Crashes

When a predicate crashes at runtime with SwiftData.PredicateError or NSInvalidArgumentException:

  1. Simplify the predicate to a single clause and add clauses back one at a time
  2. Check each clause uses only supported operations on stored properties
  3. Test on the minimum deployment target — some operations were added in later iOS versions

skills

README.md

tile.json