惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Jina AI
Jina AI
C
Cisco Blogs
博客园 - Franky
有赞技术团队
有赞技术团队
雷峰网
雷峰网
博客园 - 聂微东
WordPress大学
WordPress大学
酷 壳 – CoolShell
酷 壳 – CoolShell
NISL@THU
NISL@THU
P
Palo Alto Networks Blog
博客园_首页
阮一峰的网络日志
阮一峰的网络日志
美团技术团队
Hugging Face - Blog
Hugging Face - Blog
宝玉的分享
宝玉的分享
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
T
Threat Research - Cisco Blogs
T
Tailwind CSS Blog
T
Threatpost
D
Darknet – Hacking Tools, Hacker News & Cyber Security
W
WeLiveSecurity
大猫的无限游戏
大猫的无限游戏
V
Visual Studio Blog
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
S
SegmentFault 最新的问题
博客园 - 【当耐特】
爱范儿
爱范儿
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
A
Arctic Wolf
PCI Perspectives
PCI Perspectives
S
Secure Thoughts
The Cloudflare Blog
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
L
LINUX DO - 最新话题
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
博客园 - 三生石上(FineUI控件)
J
Java Code Geeks
The Last Watchdog
The Last Watchdog
人人都是产品经理
人人都是产品经理
罗磊的独立博客
S
Schneier on Security
腾讯CDC
Google DeepMind News
Google DeepMind News
小众软件
小众软件
量子位
N
News and Events Feed by Topic
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
Hacker News: Ask HN
Hacker News: Ask HN
V
V2EX

DEV Community

Authentication Security Deep Dive: From Brute Force to Salted Hashing (With Java Examples) Why AI Systems Don’t Fail — They Drift Spilling beans for how i learn for exam😁"Reinforcement Learning Cheat Sheet" I Replaced Chrome with Safari for AI Browser Automation. Here's What Broke (and What Finally Worked) How Python Borrows Other People's Work The $40 Architecture: Processing 1 Billion API Requests with 99.99% Uptime Vibe Coding: A Workflow Guide (From Zero to SaaS) Most webhook security guides protect the wrong side. The scary part is delivery. Headless CMS for TanStack Start: Build a Blog with Cosmic EU Age Verification App "Hacked in 2 Minutes" — What Actually Happened Comfy Cloud’s delete function does not actually remove files Running AI Models on GPU Cloud Servers: A Beginner Guide Event-driven media intelligence with AWS Step Functions and Bedrock I scored 500 AI prompts across 8 quality dimensions — here's what broke How to Call Google Gemini API from Next.js (Free Tier, No Backend Needed) The Portal Protocol: Reclaiming Human Connection in the Age of AI How to Fix Your Team's Scattered Knowledge Problem With a Self-Hosted Forum Intro to tc Cloud Functors: A Graph-First Mental Model for the Modern Cloud Designing Multi-Tenant Backends With Both Ownership and Team Access I Built a Neumorphic CSS Library with 77+ Components — Here's What I Learned PostgreSQL Performance Optimization: Why Connection Pooling Is Critical at Scale Cómo construí un SaaS multi-rubro para gestionar expensas en Argentina con FastAPI + Vue 3 🚀 I Built an Ethical Hacking Scanner Tool – Open Source Project I Replaced /usage and /context in Claude Code With a Single Statusline A Pythonic Way to Handle Emails (IMAP/SMTP) with Auto-Discovery and AI-Ready Design I Collected 8.9 Million Polymarket Price Points — Here's What I Found About How Markets Really Move EcoTrack AI — Carbon Footprint Tracker & Dashboard Everyone's Using AI. No One Agrees How. 5 self-hosted ebook managers worth trying in 2026 Building Your First AI Agent with LangChain: From Chatbot to Autonomous Assistant Common SOC 2 Failures (Real World) Stop Vibe-Checking Your AI App: A Practical Guide to Evals How to Use SonarQube and SonarScanner Locally to Level Up Your Code Quality Your Next To-Do App Is Dead — I Replaced Mine with an OpenClaw AI Sign a Nostr event in 60 lines of Python using coincurve — no nostr-sdk, no nbxplorer, no rust toolchain ITGC Audit Explained Like You’re in Big 4 Patch Tuesday abril 2026: Microsoft parcha 163 vulnerabilidades y un zero-day en SharePoint Stop scraping everything: a better way to track competitor price changes Listing on MCPize + the Official MCP Registry while routing payments OUTSIDE the marketplace — how I kept 100% of my x402 revenue Building an AI-Powered Risk Intelligence System Using Serverless Architecture Why We Ripped Function Overloading Out of Our AI Toolchain Testing AI-Generated Code: How to Actually Know If It Works SaaS Churn Is Killing Your Business. Here Is What to Do About It (Without a Support Team) The Speed of AI Is No Longer Linear - And Self-Improving Models Are Why How to Implement RBAC for MCP Tools: A Practical Guide for Engineering Teams From Standard Quote to Persuasive Proposal: AI Automation for Arborists I built a CLI that scaffolds complete multi-tenant SaaS apps Axios CVE-2025–62718: The Silent SSRF Bug That Could Be Hiding in Your Node.js App Right Now The dashboard that ended our friendship Data Pipelines Explained Simply (and How to Build Them with Python) The Hidden Cost of AI Systems Nobody Talks About. undefined vs undeclared, and how typeof behaves Switching from file-based jobs to NATS/Kafka in Rust without changing code io_uring Adventures: Rust Servers That Love Syscalls Why Agentic AI is Killing the Traditional Database The POUR principles of web accessibility for developers and designers Quantum Neural Network 3D — A Deep Dive into Interactive WebGL Visualization How To Install Caveman In Codex On macOS And Windows Automation Pipeline Reliability: Why Your Workflow Breaks When Nobody Is Watching I Built an 'Open World' AI Coding Agent — It Works From ANY Folder From Freelancing to Product: A Tech Service Company's SaaS Transformation China's AI Giants: Adding Tencent Hunyuan & ByteDance Doubao to AI University (74 Providers) On the Vibe Coders and Their Lies clerk: Auto-Summarize Your Claude Code Sessions AI Weekly — 2026/04/10–04/17 | The Model Lockdown Is Here, but the Toolchain Is the Real Battleground AI 週報 — 2026/04/10–2026/04/17 模型封鎖潮來了,但工具鏈才是真戰場 Maybe this is how Open-Source apps are born... 🚀 Fine-Tune LLMs with LoRA and QLoRA: 2026 Guide tRPC v11 + Next.js App Router: End-to-End Type Safety Without the Boilerplate ShadCN UI in 2026: Why I Stopped Installing Component Libraries and Started Owning My Components SaaS Billing in React Server Components: Stripe + Supabase Without a Single `useEffect` Join our DEV Weekend Challenge — $1,000 in Prizes Across TEN winners! Submissions Due April 20 at 6:59 AM UTC. Implementing FSRS Spaced Repetition in Flutter + Supabase — Adding Memory Science to an AI Learning App "I Texted My Localhost From the Train — Claude Code Fixed the Bug Before I Got Home" I Built a Sales Prep AI and It Went Deeper Than Expected Design to Code #2: One JSON, Eleven Outputs Solving the 100M-Row Problem: A Summary Table Pattern for High-Volume Push Notification Logs Flutter Web With Wasm: What Actually Changes For Developers I Built 50 Royalty-Free Soundtracks for My Side Project in a Weekend Using AI Music Generation The Vibe Coding Security Checklist: 7 Things to Check Before You Ship Stop Letting Googlebot Guess Fix Your React App's SEO Right Desconstruindo o Streaming do LinkedIn: Como Criar um Engine de Extração de Vídeo de Alta Performance com HLS e FFmpeg (EDA Part-1) EDA (Exploratory Data Analysis) Explained With Real Life — Why Looking at Your Data Is the Most Important Step in Machine Learning Brand Relationship Management at Scale: Our 4-Touch Outreach System for 200+ Brands Why String.fromEnvironment() Might Return an Empty String in Dart JGuardrails 1.0.0 — Hardening Java LLM Apps Against Jailbreaks, Toxicity, and Prompt Injection Plan and Schedule a Full Week of Threads Content From One Claude Conversation Coding Cat Oran Ep3, Five Tables Changed Everything Updated: BFF Pattern I'm done watching freelancers get buried by 200 proposals. So I'm building the alternative. This is my first post BFS Algorithm in Java Step by Step Tutorial with Examples Tracking LLM Pricing Monthly: An Open Dataset for 22 AI Models How We Measure Content ROI on a Comparison Site: Revenue Attribution Without Perfect Data Introducing Nova AI Ops: The AI-Native Operating System for SRE Teams I built a free desktop video downloader for Windows — Grabbit How Talkie OCR Helps Vision-Impaired & Dyslexic Users Read the World Around Them VRCFaceTracking安装和iPhone面捕配置教程,有bug Even CrowdStrike Can't See Your Agents The Automation Gold Rush: What n8n Workflows and Claude Are Opening Up for Developers Right Now
WWDC 2026 - What's New in SwiftData: Sectioned Queries, Codable Attributes, and Observers
ArshTechPro · 2026-06-15 · via DEV Community

ArshTechPro

WWDC 2026's "What's new in SwiftData" session is a tight, practical one. There's no sweeping redesign here, just four targeted additions that fill gaps developers have been working around for a while. If you've ever fought SwiftData to group a list, store a type you don't own, or react to data changes outside a SwiftUI view, this release is for you.

Here's everything that's new and how to use it.

1. Sectioned fetching with @Query

Grouping a list by some property used to mean fetching everything flat and then partitioning it yourself in the view. Now @Query does it for you.

You pass a key path to the new sectionBy: parameter. The key path starts at the model root and points to the property you want to group on:

struct TripListView: View {
    @Query(sort: \Trip.startDate,
           sectionBy: \.destination)
    var trips: [Trip]

    var body: some View {
        List(selection: $selection) {
            ForEach(_trips.sections) { section in
                Section(section.id) {
                    ForEach(section) { trip in
                        TripListItem(trip: trip)
                    }
                }
            }
        }
    }
}

A few things to notice:

  • The wrapped value (trips) is still a plain [Trip], so existing code that reads it keeps working unchanged.
  • To reach the sections, you use the underscore-prefixed projected value _trips, which exposes a sections property.
  • Each section has an id (the value from your sectionBy key path, in this case the destination string) and is itself a collection of models you can iterate.

So adding sections is additive: keep your flat array where you had it, and reach for _trips.sections only where you actually want the grouping. Sorting still applies across the whole result set, which keeps section ordering predictable.

2. Storing custom types with @Attribute(.codable)

SwiftData builds a schema by inspecting your models at launch. That works automatically for its supported value types and for anything you mark @Model. It falls apart the moment you try to persist a class you don't control.

The session's example is MKMapItem.Identifier from MapKit. Add it to a model as-is and the app crashes at launch with:

Class property within Persisted Struct/Enum is not supported

The reason: SwiftData can't inspect a non-@Model class to generate a schema, and you can't go annotate a type that lives inside MapKit.

The fix in this release is a new attribute option. If the type conforms to Codable, mark the property @Attribute(.codable) and SwiftData stores the encoded representation instead of trying to model it:

import SwiftData

@Model
class Trip {
    struct Location: Codable {
        var latitude: Double
        var longitude: Double
    }

    var name: String
    var destination: String

    var startDate: Date
    var endDate: Date

    var location: Location?

    @Attribute(.codable)
    var mapItemIdentifier: MKMapItem.Identifier?
}

This is genuinely useful, but treat it as an escape hatch, not a default. The trade-offs matter:

  • Opaque to SwiftData. A codable attribute is stored as a serialized blob, so you can't use it in predicates to filter or in sort descriptors to sort.
  • No migration awareness. If the shape of the codable type changes (you add or remove a property), it won't trigger a migration. Your Codable implementation has to encode and decode in a forward- and backward-compatible way on its own.

The rule of thumb from the session: use .codable for types you don't own (framework or third-party types). For types you define, model them as @Model or use supported value types so you keep filtering, sorting, indexing, and migrations.

3. Observing query results anywhere with ResultsObserver

@Query is great, but it only lives inside SwiftUI views. It fetches when the view appears and keeps watching the store, re-rendering when results change. The problem: plenty of code isn't a SwiftUI view. A state object that derives values from your store, or an app with no SwiftUI at all (think a SceneKit game), had no clean equivalent.

ResultsObserver is that equivalent. It fetches from your store and observes for changes using Swift Observation, and it works anywhere. It supports the same primitives you already know from @Query: filtering, sorting, and the sectioning above.

The session uses it to drive a map camera that should always frame all your trips:

@Observable @MainActor
final class MapCameraController {
    private let resultsObserver: ResultsObserver<Trip>
    var bounds: MapCameraBounds?
    private var token: ObservationTracking.Token?

    init(modelContext: ModelContext) throws {
        resultsObserver = try ResultsObserver<Trip>(modelContext: modelContext)

        token = withContinuousObservation(options: [.didSet]) { [weak self] event in
            guard let self else { return }
            self.bounds = self.calculateBounds(trips: self.resultsObserver.results)
        }
    }

    private func calculateBounds(trips: [Trip]) -> MapCameraBounds? { /* ... */ }
}

How it fits together:

  • You create a ResultsObserver for the model. No predicate and no section key path here means "give me everything."
  • withContinuousObservation(options: [.didSet]) gives you a callback whenever the results change. Read resultsObserver.results inside the closure to get the current set.
  • The call returns an ObservationTracking.Token. That token defines the lifetime of the observation, so store it on the object to keep updates flowing for as long as the object lives. Drop the token and observation stops.

In the demo, deleting a trip fires the observation, recalculates the bounds, and the map re-frames. The mental model is "@Query, but for non-view code."

A naming note: the session and Apple's chapter summaries call this ResultsObserver, while Apple's published sample snippet writes ModelResultsObserver<Trip>. Check the final SwiftData headers in your SDK for the exact spelling when you adopt it.

4. Reacting to store changes with HistoryObserver

The second observer targets a different problem: syncing and reacting to changes rather than reading current results.

Quick refresher on SwiftData history. Every time your store is saved, SwiftData records a history transaction describing what changed, where the change came from (the author), and a token that uniquely identifies it. You fetch newer transactions with ModelContext.fetchHistory. (The WWDC 2024 session "Track model changes with SwiftData history" covers the foundations.)

HistoryObserver makes reacting to that history easy. It exposes a single observable property, eventCounter, which increments whenever new transactions land. You observe the counter, and when it ticks, you fetch and process the new history. You can also filter by model type and by transaction author, which is what makes server sync clean:

@SyncActor
final class ServerSync {
    private var observer: HistoryObserver?
    private var token: ObservationTracking.Token?

    func start() throws {
        let observer = try HistoryObserver(
            authors: ["App"],
            modelContainer: modelContainer
        )
        self.observer = observer

        token = withContinuousObservation(options: .didSet) { [weak self] _ in
            // Touch eventCounter so Swift Observation tracks it
            _ = self?.observer?.eventCounter
            self?.processChanges()
        }
    }

    private func processChanges() {
        // Use ModelContext.fetchHistory to fetch and upload changes
    }
}

The important details:

  • Filtering by authors: ["App"] means you only see changes your app made. That's how you avoid replaying server-originated changes back to the server in an infinite loop.
  • You must actually read eventCounter inside the observation closure. Swift Observation only tracks what you touch, so reading the property is what registers the dependency.
  • Same lifetime rule as ResultsObserver: hold onto the ObservationTracking.Token for as long as you want to keep observing.

This is the tool for keeping a server, an app extension, or any external system in sync with what's happening in your store.

When to reach for which

A quick way to keep the two observers straight:

  • Use ResultsObserver when you need the current set of models outside a SwiftUI view and want to recompute when they change (state objects, non-SwiftUI apps, derived values).
  • Use HistoryObserver when you care about the stream of changes themselves, especially for syncing with something outside your app.

Inside a SwiftUI view, @Query is still your first choice; the observers are for everywhere else.

Wrapping up

This year's SwiftData is about filling gaps rather than reinventing anything:

  • Sectioned fetching moves grouping into @Query with sectionBy:.
  • @Attribute(.codable) is an explicit escape hatch for persisting types you don't own, at the cost of querying, sorting, and migration awareness.
  • ResultsObserver brings @Query-style fetching and observation to non-SwiftUI code.
  • HistoryObserver gives you a simple, observable signal for reacting to persistent-history changes.

None of these are flashy, but each removes a real workaround. If you've been dropping into manual fetches or hand-rolled grouping, this release lets you delete some code.