Context-aware routing to Swift/iOS development patterns, architecture, and best practices. Use when working with .swift files, ViewModels, Coordinators, refactoring, or discussing Swift/SwiftUI patterns.
Context-aware routing to iOS development patterns, code style, and architecture guidelines. This skill provides critical rules and points you to comprehensive documentation.
.swift files// Generated using Sourcery/SwiftGenLoc.*)Before completing any task:
Loc constants)SwiftUI views have three key qualities:
Key insight: Views are VALUE TYPES (structs), not long-lived objects. They are descriptions of current UI state. Breaking views into subviews doesn't hurt performance - SwiftUI maintains efficient data structures behind the scenes.
// Declarative: describe the result, not the steps
List(pets) { pet in
HStack {
Text(pet.name)
Spacer()
Text(pet.species)
}
}
// No need to manually add/remove rows - SwiftUI handles it
For detailed SwiftUI patterns, see swiftui-patterns-developer skill.
@MainActor
final class ChatViewModel: ObservableObject {
@Published var messages: [Message] = []
@Injected(\.chatService) private var chatService
func sendMessage(_ text: String) async {
// Business logic here
}
}
@MainActor
final class ChatCoordinator: ObservableObject {
@Published var route: Route?
enum Route {
case settings
case memberList
}
}
extension Container {
var chatService: Factory<ChatServiceProtocol> {
Factory(self) { ChatService() }
}
}
// Usage in ViewModel
@Injected(\.chatService) private var chatService
Keep ViewModel init() cheap - defer heavy work to .task:
// Init assigns parameters only
init(id: String) {
_model = State(wrappedValue: ViewModel(id: id))
}
// Heavy work in .task
.task { await model.startSubscriptions() }
For expensive init, defer creation entirely:
@State private var model: ViewModel?
.task(id: id) { model = ViewModel(id: id) }
Prefer AsyncStandardButton over manual loading state management for cleaner code:
// ❌ AVOID: Manual loading state
struct MyView: View {
@State private var isLoading = false
var body: some View {
StandardButton(.text("Connect"), inProgress: isLoading, style: .secondaryLarge) {
isLoading = true
Task {
await viewModel.connect()
isLoading = false
}
}
}
}
// ✅ PREFERRED: AsyncStandardButton handles loading state automatically
struct MyView: View {
var body: some View {
AsyncStandardButton(Loc.sendMessage, style: .primaryLarge) {
try await viewModel.onConnect()
}
}
}
// ViewModel can throw - errors are handled automatically
func onConnect() async throws {
guard let identity = details?.identity, identity.isNotEmpty else { return }
if let existingSpace = spaceViewsStorage.oneToOneSpaceView(identity: identity) {
pageNavigation?.open(.spaceChat(SpaceChatCoordinatorData(spaceId: existingSpace.targetSpaceId)))
return
}
let newSpaceId = try await workspaceService.createOneToOneSpace(oneToOneIdentity: identity)
pageNavigation?.open(.spaceChat(SpaceChatCoordinatorData(spaceId: newSpaceId)))
}
Benefits of AsyncStandardButton:
inProgress state internally@Published var isLoading needed)async throws - use try await and let errors propagate naturallyAnytype/Sources/
├── ApplicationLayer/ # App lifecycle, coordinators
├── PresentationLayer/ # UI components, ViewModels
├── ServiceLayer/ # Business logic, data services
├── Models/ # Data models, entities
└── CoreLayer/ # Core utilities, networking
TypeName+Feature.swiftFull Guide: Anytype/Sources/IOS_DEVELOPMENT_GUIDE.md
For comprehensive coverage of:
NEVER commit without explicit user request - Committing is destructive
Used rm -f .../PublishingPreview*.swift - deleted main UI component
ls firstRefactored dependencies but forgot MockView.swift
rg "oldName" --type swiftLOCALIZATION_GUIDE.md - Localization systemCODE_GENERATION_GUIDE.md - Feature flags, make generateDESIGN_SYSTEM_MAPPING.md - Icons, typographyNavigation: This is a smart router. For deep technical details, always refer to IOS_DEVELOPMENT_GUIDE.md.
npx skills add anyproto/ios-dev-guidelines下载完整 Skill 目录,包含 SKILL.md 及所有相关文件
Search for places (restaurants, cafes, etc.) via Google Places API proxy on localhost.
Interact with GitHub using the `gh` CLI. Use `gh issue`, `gh pr`, `gh run`, and `gh api` for issues, PRs, CI runs, and advanced queries.
Create or update AgentSkills. Use when designing, structuring, or packaging skills with scripts, references, and assets.
Start voice calls via the OpenClaw voice-call plugin.
Notion API for creating and managing pages, databases, and blocks.
Gemini CLI for one-shot Q&A, summaries, and generation.
Category:developer