För att hålla ett SwiftUI-ark öppet under uppdateringar, bevara dess presentationsvärds identitet och håll dess presentationsbindning aktiv. Koppla arket till en stabil container så att ändrande underordnat innehåll kan uppdateras utan att byta ut presentatören.

Den här guiden riktar sig till en utvecklare som bygger en Mac-app med ett redigerbart ark som ska förbli synligt medan det underliggrenda gränssnittet förändras. Det genomarbetade exemplet använder syntetisk lokal text och separerar tre saker du kan inspektera oberoende av varandra: presentationsstatus, presentande vys livslängd och redigerarens innehåll.

Varför kan en vyuppdatering få ett ark att försvinna?

SwiftUI kan skapa nya vyvärderingar när body utvärderas samtidigt som identiteten för den visade vyn bevaras. Status kvarstår för den identitetens livslängd. Att ta bort vyn eller ändra dess identitet avslutar den livslängden; att växla mellan villkorliga grenar kan också skapa distinkta identiteter, även när båda grenarna innehåller samma vytyp. Apple förklarar dessa relationer i Demystify SwiftUI.

För ett booleskt drivet ark är den dokumenterade presentationskontrollen bindningen som skickas till sheet(isPresented:onDismiss:content:): ett sant värde begär presentation. När man undersöker ett försvinande ark, kontrollera både den bindningen och den presentande vyforts existens. Ett sant värde lagrat annorstädes etablerar inte att den ursprungliga presentationsvärden överlevde. Se Apples Boolesk ark dokumentation.

En särskilt direkt orsak är ett föränderligt explicit identifierare. Apple dokumenterar att att ändra värdet som tillhandahålls till id(_:) återställer vyns identitet, inklusive dess status. Inspektera den presentande vyn och dess förfäder efter identifierare härledda från revisionsräknare, redigerbar text eller nyskapade värden. Ta bort sådana identifierare när deras återställningsbeteende är oavsiktligt. Se id(_:).

Den praktiska designslutsatsen är att placera ark-modifieraren utanför den föränderliga delen av gränssnittet. Om en laddningsvy, en filtrerad rad eller en alternativ detaljlayout kan försvinna, är dess närmaste lämpliga beständiga förfader vanligtvis en bättre presentationsägare.

Bygg en stabil arkägare med ett komplett Mac-exempel

Skapa en macOS SwiftUI-app i Xcode, sätt dess distributionsmål till macOS 12 eller senare, och ersätt de genererade app- och innehållsvy-deklarationerna med följande enda fil. Behåll endast en @main app-deklaration. macOS 12-baslinjen tillgodoser exempelts dismiss miljö-åtgärd; TextEditor är själv tillgänglig från macOS 11. Se Apples dismiss dokumentation och TextEditor dokumentation.

Fönstrets rotvy äger presentationsflaggan, redigerbar text, revisionsräknare och layoutflagga. Dess yttre VStack bär ark-modifieraren. Endast innehållet inuti den containern ändrar grenar. Apple rekommenderar att deklarera status privat på den högsta vyn som behöver den och skicka bindningar till barn som behöver ändra den. Se State.

import SwiftUI

@main
struct StableSheetDemoApp: App {
    var body: some Scene {
        WindowGroup {
            SheetOwnerView()
        }
    }
}

struct SheetOwnerView: View {
    @State private var isEditorPresented = false
    @State private var note = "Sample note Alpha"
    @State private var revision = 0
    @State private var compactLayout = false

    var body: some View {
        VStack(alignment: .leading, spacing: 16) {
            Text("Local Notes")
                .font(.title)

            if compactLayout {
                Text("Compact summary: revision \(revision)")
            } else {
                VStack(alignment: .leading, spacing: 8) {
                    Text("Expanded summary")
                    Text("Revision \(revision)")
                    Text(note)
                }
            }

            Button("Edit Note") {
                isEditorPresented = true
            }
        }
        .padding(24)
        .frame(minWidth: 440, minHeight: 260)
        .sheet(isPresented: $isEditorPresented) {
            NoteEditorSheet(
                note: $note,
                revision: $revision,
                compactLayout: $compactLayout
            )
        }
    }
}

struct NoteEditorSheet: View {
    @Binding var note: String
    @Binding var revision: Int
    @Binding var compactLayout: Bool
    @Environment(\.dismiss) private var dismiss

    var body: some View {
        VStack(alignment: .leading, spacing: 16) {
            Text("Edit Sample Note")
                .font(.headline)

            TextEditor(text: $note)
                .frame(minHeight: 160)

            Text("Owner revision: \(revision)")

            Button("Update Owner") {
                revision += 1
                compactLayout.toggle()
            }

            HStack {
                Spacer()
                Button("Done") {
                    dismiss()
                }
            }
        }
        .padding(24)
        .frame(width: 460, height: 340)
    }
}

Detta är en komplett demonstrationsapp, inspektad mot de dokumenterade API:erna. Den har inte kompilerats eller körts här eftersom den här miljön saknar Swift-verktygskedja eller macOS-körning.

Hur man utövar uppdateringen utan att stänga arket

  1. Kör appen och klicka på Redigera anteckning.
  2. Ersätt exempeltexten med Exempelanteckning Beta.
  3. Klicka på Uppdatera ägare flera gånger. Varje klick ökar ägarens status och växlar ägarens villkorliga innehåll.
  4. Bekräfta att redigeraren förblir synlig, dess text förblir Exempelanteckning Beta, och dess revisionsvisning avancerar.
  5. Klicka på Klar. Bekräfta att fönstret visar den redigerade texten i den expanderade layouten när den layouten är aktiv.
  6. Öppna redigeraren igen och bekräfta att den redigerade texten förblir tillgänglig.

Uppdateringsknappen finns inuti arket så att testet inte beror på att klicka på det underliggande fönstret. AppKit dokumenterar ark som dokumentmodala: medan ett ark är synligt, är de flesta händelser riktade mot dess föräldrafönster förbjüdna. Att uppdatera ägaren genom en bindning låter det här exemplet utöva tillståndsändringen direkt. Se beginSheet(_:completionHandler:).

Bestäm vad att stänga redigeraren ska betyda

Det här exemplet redigerar ägarens text omedelbart. Klar stänger redigeraren; det utför inte en separat sparaoperation. Strängen finns kvar i fönsterlokalt tillstånd, och exemplet tillhandahåller ingen persistens över appstartar. Det beteendet följer den delade bindningsdesignen som beskrivs i State.

Om din uppgift kräver ett avbrytningsbart utkast, använd ett separat utkastvärde och kopiera det till dokumentet först vid en explicit bekräftelseåtgärd. Definiera det beteendet innan du implementerar avvisning: att bestämma om man ska genomföra eller kassera ett utkast är separat från att bestämma vilken vy som äger arket.

Diagnostisera avvisningen med tre oberoende kontroller

Använd följande sekvens på din egen app. Den vänder de allmänna identitetsreglerna till en fokuserad undersökning, utan att anta att varje försvinande ark har samma orsak.

Kontroll Vad att inspektera Praktisk korrigering
Presentationsvärde Varje skrivning som sätter booleskt till false eller rensar det valfria presentationsobjektet Håll avvisningsskrivningar i avsiktliga stäng-åtgärder
Presentatörsidentitet Villkorliga grenar, borttagna rader, föränderliga förfaderidentifierare Flytta både presentationsstatus och modifieraren till en lämplig stabil förfader
Innehållslivslängd Ark-lokal status, föränderliga innehållsidentifierare, redigerarsynkronisering Bevara den avsedda redigeringssessionen och uppdatera befintligt innehåll medvetet

Först, sök i ditt projekt efter tilldelningar till presentations-egenskapen och anrop till dismiss(). En uppdaterings-callback kan explicit stänga arket. Läs dismiss inuti arkets egen vy, som exemplet gör: Apple dokumenterar att åtgärden gäller den miljö där den erhålls. Att läsa den i fönstrets rotvy kan rikta in sig på det fönstret istället. Se dismiss.

Andra, inspektera hierarkin ovanför modifieraren. Om arket är kopplat till en detaljvy som en uppdatering tar bort, flytta det ovanför den ersättningsgränsen. Flytta dess lokalt ägda presentationsstatus också. Att behålla flaggan i ett barn vars identitet upphör lämnar lagringen sårbar för ersättning, enligt Apples vy livslängd förklaring.

Tredje, skilja en stängd presentation från en redigerare som förblir synlig men förlorar sitt utkast. Börja med det enkla TextEditor-exemplet, lägg sedan till ditt anpassade innehåll tillbaka i etapper. Denna jämförelse är en diagnostisk metod: den hjälper avgöra om felet följer presentationsägarskap eller din innehållsuppdateringslogik.

Bör du byta till ett objekt-drivet ark?

Använd sheet(item:onDismiss:content:) när en specifikt vald entitet är källan för presentationen. Apple dokumenterar ett valfritt objekt som följer Identifiable, skickar ett icke-nil objekt in i innehållsstängningen och beskriver ersättning när objektet ändras. Att byta överlagringar bevarar inte i sig en presentatör vars livslängd upphör. Se objekt-drivna ark.

Välj en identifierare som representerar entiteten genom hela den avsedda redigeringssessionen. Swifts Identifiable-protokoll uttrycker stabil identitet, och dess dokumentation lämnar explicit den krävda varaktigheten och omfånget till de deltagande typerna. En ny identifierare varje gång en egenskap läses kan inte representera en fortsatt entitet. Se Identifiable.

För en enkel redigerare som demonstrationen, gör en boolesk presentationsflagga plus separata textbindningar den avsedda relationen lätt att inspektera. För en vald-objekt-redigerare, håll urvalsidentitet separat från ofta föränderliga fält. Behandla att välja en annan entitet som ett avsiktligt presentationsbeslut, och definiera vad som ska hända med det nuvarande utkastet först.

Kommer att inaktivera interaktiv avvisning hålla arket vid liv?

interactiveDismissDisabled(_:) kontrollerar icke-programmatisk avvisning. Apple anger explicit att det inte förhindrar avvisning orsakad av att ändra presentationsbindningen eller anropa dismiss. Dess dokumenterade roll ger därmed inget botemedel mot identitetsersättning. Se interactiveDismissDisabled(_:).

Använd modifieraren inuti ark-hierarkin bara när ditt gränssnitt behöver det avvisningsbeteendet, och behåll en explicit avslutningsväg. För den här uppgiften, börja med att bevara värden och dess status. Att lägga till en avvisningsrestriktion innan man identifierat orsaken kan lämna det ursprungliga ägarskapsproblemet olöst.

Vad ändras när arket innehåller AppKit- eller TextKit-innehåll?

För en NSTextView inbäddad med NSViewRepresentable, separera skapande från uppdateringar. Apple definierar makeNSView(context:) som skapandesteget och updateNSView(_:context:) som platsen att applicera efterföljande SwiftUI-information. En koordinator bär delegat- eller target-action-förändringar tillbaka in i SwiftUI. Se NSViewRepresentable och makeNSView(context:).

En användbar implementationsregel härledd från den livscykeln är att undvika att bygga om redigeraren bara för att orelaterad ägarstatus ändrades. Innan man byter ut dess innehåll, avgör om den inkommande modelltexten faktiskt skiljer sig och hur samtidiga lokala redigeringar ska hanteras. Ett stabilt ark löser inte, i sig, konkurrerande skrivningar till sin text.

TextKit levererar textlagring, layout och rendering. AppKits NSTextView paketerar dessa kapaciteter och exponerar moderna och äldre layoutmotorer. Den maskineriet rör redigerarens innehåll; presentationsägarskap behöver fortfarande sin egen stabila livslängd. Använd TextKit när redigeringsuppgiften kräver det, och undersök textuppdateringsbeteende separat från arkavvisning. Se Apples TextKit översikt.

När är fönsterägt AppKit-presentation lämplig?

Om din befintliga app redan äger sin fönsterlivscykel i AppKit, introducerar macOS 26 NSWindow.beginSheet(content:completionHandler:) för att presentera SwiftUI-innehåll direkt på det fönstret. Apple dokumenterar stöd för arkets dismiss-miljöåtgärd, storlekar, verktygsfält och interaktiv-avvisningskontroll. Använd en macOS 26 SDK och tillämpa macOS 26-tillgänglighetsgränsen innan du antar det. Se beginSheet(content:completionHandler:).

Den returnerade NSWindow.HostingSheetRepresentation kan ändra den presenterade rotvyn eller stödja programmatisk avvisning från AppKit. Det erbjuder ett dokumenterat alternativ när fönsternivå-ägarskap passar appens arkitektur. Det är onödigt för det stabila SwiftUI-container-exemplet ovan. Se NSWindow.HostingSheetRepresentation.

för tidigare macOS-versioner, accepterar AppKits befintliga beginSheet(_:completionHandler:) ett NSWindow-ark och dokumenterar presentationskö. Anta inte att den nyare SwiftUI-innehålls-överlagringen är tillgänglig på dessa system. Se beginSheet(_:completionHandler:).

Håll ägaren stabil, håll presentationsvärdet aktivt, och bevara redigerares avsedda sanningskälla. Verifiera dessa villkor med en liten lokal uppdateringsåtgärd innan du återställer mer komplext innehåll. Detta ger dig ett konkret sätt att fortsätta redigera medan gränssnittet uppdateras, inom de livslängds- och API-gränser Apple dokumenterar.

Källor