Fehlerbehebung
Von Build-Fehlern über die Lebensdauer von Zustand bis zu Rendering-Fehlern – der kürzeste Weg zur Ursache.
Build-Fehler
invalid fingerprint
Der Fingerprint einer Vorlage lässt sich nicht wiederverwenden. Löschen Sie die Zeile .fingerprint in build.zig.zon, führen Sie einmal zig build aus und fügen Sie den eindeutigen Wert ein, den Zig ausgibt.
import of file outside module path
Führen Sie zig test nicht direkt auf Framework-interne Dateien aus. Verwenden Sie die Test-Steps des Repos wie zig build test-ui (siehe Befehle).
@import("ui") / @import("zenit_app") not found
Prüfen Sie, ob build.zig.zon die Abhängigkeit .zenit deklariert und ob Sie nach dem Erstellen des Executables zenit.attach(zenit_dep, exe) aufrufen – es fügt die Module ui / zenit_app hinzu, kompiliert die macOS-Bridges und linkt die System-Frameworks.
build API field mismatch
Führen Sie zuerst zig version aus. zenit benötigt Zig 0.15.2 (minimum_zig_version in build.zig.zon); die Build-APIs anderer Versionen werden nicht unterstützt.
-Dtest-mode=true has no effect
Zig isoliert Abhängigkeitsoptionen. Reichen Sie .@"test-mode" und .@"e2e-port" in b.dependency("zenit", ...) explizit weiter, wie es templates/minimal-app/build.zig tut.
Laufzeit und Zustand
error.StateNotFound
Ein cx.handler(State, id, method) mit expliziter ID lief, bevor dieser Zustand existierte. Verwenden Sie besser cx.bindState + cx.on: Sie übergeben den Zustandszeiger direkt, es gibt keine IDs zu verwalten.
leaked ArrayList / HashMap at exit
Zustand aus bindState gehört dem Cx und wird mit ihm freigegeben; deklariert T ein pub deinit(self: *T), ruft das Framework es automatisch auf. Ein Leak bedeutet meist, dass deinit nicht pub ist oder die Ressource der Lebensdauer einer Seite hätte folgen sollen. Siehe nächsten Abschnitt.
crash after switching pages
Suchen Sie nach einem *Node oder *Scope der vorherigen Seite im globalen Zustand. Sobald der Scope der Seite freigegeben ist, sind diese Zeiger ungültig und müssen mit ihm gelöscht werden.
Invalid free after updating text
Der aktuelle Text des Knotens kann eine Kopie sein, die dem Knoten gehört. Ändern Sie nicht content an Props aus getText(), um sie per setText zurückzugeben; verwenden Sie try node.setTextContent(cx.allocator, "Updated"), das den String kopiert und den Besitz korrekt markiert.
Zustand richtig aufräumen
Legen Sie im Zustand ein allocator-Feld an und überlassen Sie das Aufräumen einem pub deinit. Der Anfangswert darf noch keine Ressourcen besitzen – allozieren Sie nach bindState.
const Editor = struct {
allocator: std.mem.Allocator,
lines: std.ArrayList([]const u8) = .empty,
// pub: the Cx calls this automatically when it frees the state.
pub fn deinit(self: *Editor) void {
self.lines.deinit(self.allocator);
}
};
// The initial value must not own resources yet; allocate after binding.
const editor = try cx.bindState(Editor, .{ .allocator = cx.allocator });Greifen Sie nur dann zu scope.onCleanup, wenn das Aufräumen kein pub deinit ist oder die Ressource einem Scope (einer Seite) statt dem ganzen Cx folgen muss.
// Resources that must follow a page (Scope), not the whole window (Cx).
const PageCache = struct {
allocator: std.mem.Allocator,
map: std.StringHashMapUnmanaged(u32) = .empty,
// Not named `pub fn deinit`: the Cx would call it again and double-free.
fn release(self: *PageCache) void {
self.map.deinit(self.allocator);
}
};
const cache = try cx.bindState(PageCache, .{ .allocator = cx.allocator });
try scope.onCleanup(PageCache, cache, PageCache.release);Layout und Zeichnen
state changed but the text did not
setText vergleicht bereits alte und neue Signatur und markiert sizing / render dirty bei Bedarf – kein manuelles markRenderDirty nötig. Veralteter Text bedeutet meist, dass eine TextProps-Kopie ohne Aufruf von setText geändert wurde oder der angezeigte Wert sein Signal nie abonniert hat. Verwenden Sie besser ui.textFmt(cx, scope, fmt, .{ signals }, props), um Signals / Memos direkt zu abonnieren.
some colors ignore a theme switch
boxStyled / textStyled und Co. hängen einen on_theme-Hook an, und cx.setTheme spielt diese nur im Teilbaum von cx.root erneut ab; einfache Knoten und Komponenten-Styles sind Momentaufnahmen vom Mount. Bauen Sie diese Bäume beim Theme-Wechsel neu auf, oder abonnieren Sie cx.themeSignal(scope) in einem Effect und stylen Sie neu; Knoten, die nicht unter cx.root hängen, werden ebenfalls nicht aktualisiert.
clicks fall through an overlay’s empty area
Rein visuelle Container ohne Interaktion sind standardmäßig pass_through. Setzen Sie hit_behavior = .@"opaque" in der Style-Erweiterung der Overlay-Wurzel – oder verwenden Sie Modal / Sheet, die ihre eigene Barriere mitbringen.
a huge invisible hit area in the window
Hängen Sie ui.devtools.overlay an, um den getroffenen Knoten zu untersuchen, und geben Sie sein Bildschirm-Rect mit node.globalRect() aus. Übliche Ursache ist ein fill-/grow-Sizing des Elternknotens oder eine zu große absolute Position; prüfen Sie bei ausgeblendeten Overlays, ob sie aus dem Hit-Testing entfernt sind – ein mit node.setDisplay(.none) ausgeblendeter Teilbaum verlässt Layout, Zeichnen, Hit-Testing und Tab-Navigation als Ganzes.
// Plain visual containers are pass-through by default.
// Make an overlay root swallow clicks on its empty area:
(try panel.style.ensureExtFallible(cx.allocator)).hit_behavior = .@"opaque";Immer noch festgefahren
Wenn Sie ein Issue melden, fügen Sie mindestens Folgendes bei:
- ✓
Versionen: die zenit-Revision,
zig versionund Ihre macOS-Version. - ✓
Reproduktion: ein minimales Beispiel und der ausgeführte Build-Step.
- ✓
Ausgabe: die vollständige Fehlerausgabe, nicht nur die letzte Zeile.
- ✓
Rendering-Probleme: ein Screenshot sowie die Größen der betroffenen Knoten aus DevTools.