swiftui-component — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited swiftui-component (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
Ask if not already provided:
@Observable vs ObservableObject)| iOS Target | Pattern |
|---|---|
| iOS 17+ | @Observable macro on ViewModel, @State private var viewModel in View |
| iOS 16 and below | ObservableObject + @Published, @StateObject in View |
Always generate two files: one View, one ViewModel.
View template (iOS 17+ / @Observable):
// Features/[Name]/[Name]View.swift
import SwiftUI
struct [Name]View: View {
@State private var viewModel: [Name]ViewModel
init(viewModel: [Name]ViewModel = [Name]ViewModel()) {
_viewModel = State(initialValue: viewModel)
}
var body: some View {
content
.task { await viewModel.onAppear() }
.alert("Error", isPresented: .constant(viewModel.error != nil)) {
Button("OK") { viewModel.dismissError() }
} message: {
Text(viewModel.error?.localizedDescription ?? "")
}
}
@ViewBuilder
private var content: some View {
if viewModel.isLoading {
ProgressView()
} else {
mainContent
}
}
private var mainContent: some View {
// Primary UI here
Text(viewModel.title)
.accessibilityLabel(viewModel.title)
}
}
#Preview {
[Name]View(viewModel: [Name]ViewModel())
}View template (iOS 16 / ObservableObject):
// Features/[Name]/[Name]View.swift
import SwiftUI
struct [Name]View: View {
@StateObject private var viewModel: [Name]ViewModel
init(viewModel: [Name]ViewModel = [Name]ViewModel()) {
_viewModel = StateObject(wrappedValue: viewModel)
}
var body: some View {
// same structure as above
}
}ViewModel template (iOS 17+ / @Observable):
// Features/[Name]/[Name]ViewModel.swift
import Foundation
import Observation
@MainActor
@Observable
final class [Name]ViewModel {
// MARK: - Output State
private(set) var isLoading = false
private(set) var title: String = ""
private(set) var error: Error?
// MARK: - Dependencies
private let service: [Service]Protocol
init(service: [Service]Protocol = [Service]()) {
self.service = service
}
// MARK: - Actions
func onAppear() async {
isLoading = true
defer { isLoading = false }
do {
title = try await service.fetchTitle()
} catch {
self.error = error
}
}
func dismissError() {
error = nil
}
}ViewModel template (iOS 16 / ObservableObject):
// Features/[Name]/[Name]ViewModel.swift
import Foundation
@MainActor
final class [Name]ViewModel: ObservableObject {
@Published private(set) var isLoading = false
@Published private(set) var title: String = ""
@Published private(set) var error: Error?
private let service: [Service]Protocol
init(service: [Service]Protocol = [Service]()) {
self.service = service
}
func onAppear() async {
isLoading = true
defer { isLoading = false }
do {
title = try await service.fetchTitle()
} catch {
self.error = error
}
}
func dismissError() {
error = nil
}
}Before finalizing, verify:
import SwiftUI (only Foundation, Observation)init#Preview compiles with default / mock data.accessibilityLabel where neededIf the view body grows complex (>50 lines), extract sub-views:
// Inline private sub-view (same file — preferred for small extractions)
private extension [Name]View {
var headerSection: some View {
VStack(alignment: .leading) {
// ...
}
}
}For reusable components, create a separate file in Core/Components/.
User says: "Create a SwiftUI product list screen that fetches products and shows a loading spinner"
Files generated:
ProductListView.swift — list with .task, loading overlay, error alertProductListViewModel.swift — fetches from ProductRepositoryProtocol, manages loading/error stateUser says: "Build a profile detail screen showing user name, avatar, bio, and a logout button"
Files generated:
ProfileView.swift — avatar (AsyncImage), name, bio, logout buttonProfileViewModel.swift — onLogout() action, user state, logout confirmation flagUser says: "Create a settings screen with a toggle for notifications and a text field for display name"
Files generated:
SettingsView.swift — Form with Toggle and TextField bound to ViewModelSettingsViewModel.swift — notificationsEnabled, displayName, save() async actionPreview crashes: ViewModel has a real dependency with side effects. Add a static var preview: [Name]ViewModel with a mock service, or make the default init safe for previews.
View body is growing too large: Extract into private @ViewBuilder computed properties or private extension sub-views. If a sub-view needs significant logic, give it its own ViewModel.
State not updating in view: For @Observable, ensure @State is used in the View (not @StateObject). For ObservableObject, ensure @Published is on the property.
~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.