Production-ready SwiftUI starter kit demonstrating modern Apple platform development with Swift 6, strict concurrency, iCloud sync, and professional architecture.
A comprehensive starter kit for building native iOS and macOS apps with modern best practices. Showcases a complete, working application architecture you can use as a foundation for your own projects.
What you get:
- Complete SwiftUI app with iOS and macOS support
- Swift 6 strict concurrency patterns
- Four storage patterns (UserDefaults, iCloud Key-Value Store, Keychain, SwiftData)
- Modern data persistence with SwiftData and iCloud sync
- App services stubs (push notifications, background tasks, universal links)
- Full accessibility support (VoiceOver, Dynamic Type)
- Modern localization with String Catalog (Spanish included)
- Comprehensive testing infrastructure (unit + UI tests)
- Professional development tooling (SwiftLint, SwiftFormat, git hooks)
- Clean architecture with Swift Package Manager
- Cross-platform patterns for iOS/iPadOS/macOS
- Feature planning documentation workflow
Origin: Evolved from Cumbersome, a production iOS/macOS app. All chat functionality removed, leaving clean storage pattern demonstrations and professional architecture.
- iOS 18+ / iPadOS 18+ / macOS 15+
- Swift 6.0+ with strict concurrency
- Xcode 16+
git clone https://github.com/foldingsky/FoldingKit.git
cd FoldingKit
make setup # Install tools and configure git hooks
open FoldingKit.xcodeprojSelect your target device/simulator and press
Fully automated process:
- (Optional) Bump version in Xcode if releasing new version:
- Open Xcode → Select target → General tab
- Change Version:
1.2.0→1.3.0 - Save and close Xcode
- Sync version and increment build:
./scripts/update-version.sh
- In Xcode, go to
Product > Archive - Distribute to App Store Connect
- Run release command to tag and create GitHub releases:
make release
- Push commits to remote:
git push
That's it! 🎉
What this does automatically:
- ✅ Reads version from Xcode project (
MARKETING_VERSION) - ✅ Auto-increments build number (
CURRENT_PROJECT_VERSION) - ✅ Syncs all
MARKETING_VERSIONvalues inproject.pbxprojto be consistent - ✅ Commits version bump
- ✅ Generates
CHANGELOG.mdfrom conventional commits - ✅ Commits the changelog
- ✅ Creates and pushes git tags for both iOS and macOS
- ✅ Creates GitHub releases with changelog as release notes
- ✅ Handles edge cases (no commits, no version change, etc.)
Note: Version numbers are displayed via AppVersion.version which reads
from the Bundle at runtime, so Swift files don't need updating!
Single platform only (if needed):
make release PLATFORM=ios # iOS only
make release PLATFORM=macos # macOS onlyManual override (if you need explicit control):
make release-manual VERSION=1.0.0 BUILD=3 [PLATFORM=ios|macos|both]Notes:
- Build numbers never reset - they increment forever across versions
- Version 1.2.0 might have builds 1-3, then 1.3.0 continues with builds 4-6
- Every build has a unique number across entire project history
- Works even if old commits don't follow conventional format
Manual changelog generation (preview without releasing):
make changelog # Updates CHANGELOG.md from commit historyTo publish your app to the App Store, you need to set up App Store Connect and integrate it with your Xcode project.
Initial Setup (one-time):
-
Enroll in Apple Developer Program
- Visit https://developer.apple.com/programs/
- Cost: $99/year for individuals or organizations
- You'll receive a Team ID (e.g.,
4FQ4HSL278)
-
Create App Records in App Store Connect
- Visit https://appstoreconnect.apple.com
- Go to My Apps → + → New App
- Create separate app records for iOS and macOS (if supporting both):
- iOS App: Select iOS platform, choose unique Bundle ID
- macOS App: Select macOS platform, choose unique Bundle ID
- Fill in required metadata:
- App Name
- Primary Language
- Bundle ID (must match your Xcode project)
- SKU (unique identifier for your records)
-
Configure Certificates & Provisioning
- In Xcode: Project → Signing & Capabilities
- Select your Team (automatically creates certificates)
- Enable Automatic Signing for development
- For distribution, Xcode handles this during Archive
-
Enable iCloud (if using sync features)
- In App Store Connect → Your App → Features → iCloud
- Enable iCloud for your app
- In Xcode → Target → Signing & Capabilities → + Capability → iCloud
- Enable iCloud Documents and/or CloudKit
- Container ID should match:
iCloud.$(CFBundleIdentifier)
For Each Release:
-
Archive in Xcode (step 3 in release process above)
- Product → Archive
- Wait for build to complete
-
Distribute to App Store Connect
- Organizer window appears automatically after archive
- Click Distribute App
- Select App Store Connect
- Select Upload (not Export)
- Follow prompts:
- ✅ Include bitcode for iOS apps (optional)
- ✅ Upload symbols for crash reports
- ✅ Automatically manage signing
- Click Upload
-
Wait for Processing (5-30 minutes)
- App Store Connect will process your build
- You'll receive email when ready
-
Submit for TestFlight or App Review
TestFlight (beta testing):
- App Store Connect → TestFlight → Select your build
- Add internal testers (up to 100, no review needed)
- Add external testers (requires Apple review, up to 10,000)
- Provide test information and beta app description
App Store Submission:
- App Store Connect → App Store → Select version
- Click + to add new version
- Select the build you uploaded
- Complete all required fields:
- Version information
- Screenshots (required sizes for each device type)
- App description, keywords, support URL
- Age rating questionnaire
- App Review Information (contact info, notes for reviewers)
- Submit for Review
-
Monitor Review Status
- Waiting for Review (1-3 days typical)
- In Review (a few hours to 1 day)
- Pending Developer Release or Ready for Sale (you made it!)
- Rejected (address issues and resubmit)
Common Issues:
- Missing Compliance: Export compliance required for apps with encryption
- Most apps use encryption (even HTTPS)
- Add
ITSAppUsesNonExemptEncryptionkey toInfo.plist - Set to
falseif only using standard encryption
- Missing Screenshots: Required for each device size you support
- Invalid Provisioning: Ensure Bundle ID matches App Store Connect exactly
- Capabilities Mismatch: Entitlements in Xcode must match App Store Connect
Helpful Links:
- App Store Connect: https://appstoreconnect.apple.com
- Developer Portal: https://developer.apple.com/account
- Review Guidelines: https://developer.apple.com/app-store/review/guidelines/
- TestFlight Guide: https://developer.apple.com/testflight/
Step 1: Rename the Project
In Xcode:
- Select project in navigator → rename
FoldingKittoYourApp - Rename app target to
YourApp - Product → Scheme → Manage Schemes → rename schemes
Step 2: Update Bundle Identifier
Target → General → Identity:
Bundle Identifier: com.yourcompany.yourapp
Update in entitlements files:
YourApp/YourApp.entitlementsYourApp/YourApp-Dev.entitlements
Change iCloud.com.foldingsky.foldingkit to iCloud.com.yourcompany.yourapp
Step 3: Update Development Team
In Xcode project settings or directly in project.pbxproj:
DEVELOPMENT_TEAM = YOUR_TEAM_ID;
Currently set to 4FQ4HSL278 (for FoldingKit App Store publishing). You MUST
change this to your own team ID.
Step 4: Update Package Name
In Package.swift, rename:
name: "FoldingKitCore" → "YourAppCore"Then update all imports:
import FoldingKitCore → import YourAppCoreStep 5: Replace Assets
- App icons in
Assets.xcassets/AppIcon.appiconset/ - Logo images in
AppLogoDark.imageset/andAppLogoLight.imageset/ - Accent colors in
AccentColor.colorset/
Step 6: Update Contact Info
Replace in FeedbackSectionView.swift:
- Email:
caldron.mounts-4s@icloud.com - Support URLs:
https://folding-sky.com/*
Organized as a Swift Package-based app for clean separation of concerns.
FoldingKit/
├── FoldingKit.xcodeproj/ # Xcode project
├── Package.swift # SPM manifest for `FoldingKitCore`
├── Makefile # Development commands (lint, test, format)
│
├── FoldingKit/ # Main app target
│ └── FoldingKitApp.swift # App entry point
│
├── Sources/FoldingKitCore/ # Core business logic as a Swift Package
│ ├── Models/ # Data models (SwiftData, etc.)
│ ├── Services/ # Singleton services (Keychain, iCloud)
│ ├── ViewModels/ # Observable objects driving the UI
│ ├── Views/ # Reusable SwiftUI views
│ └── Utils/ # Helper functions and extensions
│
├── Tests/ # Unit tests for `FoldingKitCore`
├── UITests/ # UI tests for the iOS app
├── MacOSUITests/ # UI tests for the macOS app
│
├── docs/ # Project documentation
├── scripts/ # Build and automation scripts
├── .cursor/rules/ # Rules for AI-assisted development
└── [config files] # .gitignore, .swiftlint.yml, etc.
FoldingKit includes AI development rules in .cursor/rules/ to help AI
assistants work effectively with the codebase. For major features, AI assistants
will automatically create planning docs in docs/ai-dev/.
Example prompt for complex features:
Add user authentication with Face ID support. Document the plan in
docs/ai-dev/and keep it updated as you implement.
The AI will create docs/ai-dev/user-auth-2025-10-27.md (or similar) tracking:
- Implementation phases
- Progress checkpoints
- Architecture decisions
- Testing strategy
See: docs/ai-dev/completed/bootstrap-2025-10-26.md for a complete example
of a transformation doc created during FoldingKit's development.
make help # Show all commands
make setup # First-time setup (tools + hooks)
make lint-fix # Auto-fix linting issues
make format # Format code
make format-check # Check formatting (CI mode)
make fix # format + lint-fix
make test # Run unit tests
make build # Build project
make ready # fix + test (pre-commit check)
make changelog # Generate CHANGELOG.md
make release # Create release (see Quick Command Help above)Hooks run automatically on commit (installed via make setup):
pre-commit:
- Auto-formats Swift files with SwiftFormat
- Auto-fixes linting issues with SwiftLint
- Ensures code quality before commit
commit-msg:
- Validates conventional commit format
- Required for automatic changelog generation
Conventional Commit Format:
<type>(<scope>): <description>
Examples:
feat: add new feature
fix(settings): resolve dark mode bug
docs: update README
Types: feat, fix, docs, style, refactor, test, chore, perf,
ci, build, revert
Note: See "Quick Command Help" section above for complete release workflow including versioning, changelog generation, and App Store Connect integration.
GitHub Actions CI/CD pipeline runs on every push and pull request:
What's Tested:
- ✅ Release build verification
- ✅ 33 unit tests (zero warnings)
- ✅ SwiftLint quality checks
- ✅ SwiftFormat validation
- ✅ Optional code coverage reporting
Infrastructure:
- macOS 15 runners with Xcode 16.2 (Swift 6.0)
- 2 parallel jobs: build+test, lint
- Smart caching for fast builds (3-5 min cached, 8-10 min first run)
Note: UI tests disabled in CI (require code signing). Unit tests provide comprehensive coverage.
Check the CI status badge above or view the Actions tab.
@Observable
@MainActor
public class YourViewModel {
public var state: YourState
public func performAction() async throws(YourError) {
// Business logic
}
}public struct YourModel: Codable, Equatable, Sendable {
public let id: UUID
public var content: String
}public final class YourService: Sendable {
public nonisolated(unsafe) static let shared = YourService()
@MainActor
public func performTask() async throws(YourError) {
// Implementation
}
}Automatic dev/prod detection for debug logging:
// Only logs in DEBUG builds (Xcode's debug configuration)
Debug.log("Starting operation")
Debug.log("✅", "Operation completed")
// Check if debug is enabled
if Debug.isEnabled {
// Expensive debug operations
}Production builds automatically strip all debug logs with zero overhead.
let coordinator = NSFileCoordinator()
let fileURL = cloudDocumentsURL.appendingPathComponent("data.json")
coordinator.coordinate(writingItemAt: fileURL, options: .forReplacing, error: &error) { url in
try data.write(to: url)
}In Xcode:
- Select target → Signing & Capabilities
- Click + Capability → iCloud
- Enable iCloud Documents
- Container auto-generates:
iCloud.$(CFBundleIdentifier)
Testing Sync:
xcrun simctl boot "iPhone 15"
xcrun simctl boot "iPhone 15 Pro"On each simulator: Settings → Sign in → enable iCloud Drive. Create data on one device, watch it sync to the other.
FoldingKit includes comprehensive test examples demonstrating best practices.
Accessibility:
- All icon-only buttons have descriptive labels for VoiceOver
- Dynamic Type support for text scaling
- Accessibility hints for non-obvious actions
- Tested with
.accessibilityExtraExtraLargepreview
Localization:
- Modern String Catalog (
Localizable.xcstrings) format - 60+ localized strings with Spanish translations
- Type-safe
String(localized:, bundle: .module)pattern - Easy to add new languages in Xcode's visual editor
All user-facing text is localized and accessibility-ready for worldwide App Store distribution.
Important: These tests are examples and documentation, not requirements.
When you customize FoldingKit for your app, delete the tests for features you
replace. For instance, when you delete SampleNote to add your own models, also
delete SampleNoteTests.swift.
Tests for all four storage patterns:
@MainActor
final class YourViewModelTests: XCTestCase {
var sut: YourViewModel!
override func setUp() async throws {
sut = YourViewModel()
}
func testFeature() async throws {
// Test implementation
}
}Run tests:
make test # Run all unit tests
swift test # SPM test commandiOS and macOS UI test examples with helper methods:
final class YourUITests: iOSUITestCase {
func testNavigation() {
navigateToSettings() // Helper method
assertElementExists(app.navigationBars["Settings"])
}
}Launch arguments:
RESET_STATE- Clear all data for fresh test state
MVVM with Swift 6:
- Models: Pure data (Sendable structs)
- ViewModels: Business logic (@MainActor, @Observable)
- Views: SwiftUI (no business logic)
- Services: Shared functionality (Singletons)
Storage Patterns:
FoldingKit demonstrates all four essential Apple platform storage patterns, giving you production-ready examples for every persistence need:
For device-specific settings that don't need to sync:
// Save
UserDefaults.standard.set(value, forKey: "preference_key")
// Load
let value = UserDefaults.standard.string(forKey: "preference_key")Example: Dark mode preference (darkModePreference)
Use for: UI preferences, device-specific settings
Pro: Fast, simple
Con: No sync across devices
For user preferences that should sync across all devices:
// Setup (in SettingsStorageManager)
let iCloudStore = NSUbiquitousKeyValueStore.default
// Save
iCloudStore.set(value, forKey: "setting_key")
iCloudStore.synchronize()
// Load
let value = iCloudStore.string(forKey: "setting_key")
// Listen for changes
NotificationCenter.default.addObserver(
forName: NSUbiquitousKeyValueStore.didChangeExternallyNotification,
object: iCloudStore,
queue: nil
) { notification in
// Handle sync from other devices
}Example: Sample feature toggle (sampleFeatureEnabled)
Use for: User preferences, feature flags, lightweight settings
Limits: 1MB total, 1024 keys max
Pro: Automatic sync, low overhead
Con: Size limits, eventual consistency
For sensitive data like passwords, tokens, API keys:
// Save
let query: [String: Any] = [
kSecClass as String: kSecClassGenericPassword,
kSecAttrAccount as String: identifier,
kSecValueData as String: data,
kSecAttrSynchronizable as String: true // iCloud Keychain sync
]
SecItemAdd(query as CFDictionary, nil)
// Load
let query: [String: Any] = [
kSecClass as String: kSecClassGenericPassword,
kSecAttrAccount as String: identifier,
kSecReturnData as String: true
]
var result: AnyObject?
SecItemCopyMatching(query as CFDictionary, &result)Example: Private data (privateData)
Use for: API keys, passwords, tokens, certificates
Pro: Encrypted, syncs via iCloud Keychain
Con: Access requires device authentication on iOS
See SettingsViewModel and SettingsStorageManager for complete
implementations.
For structured data that needs relationships, queries, and modern Swift patterns:
// Define model
@Model
final class SampleNote {
var id: UUID
var title: String
var content: String
var createdAt: Date
var tags: [String]
init(title: String, content: String = "", tags: [String] = []) {
self.id = UUID()
self.title = title
self.content = content
self.createdAt = Date()
self.tags = tags
}
}
// Add to app
.modelContainer(for: SampleNote.self)
// Query in views
@Query(sort: \SampleNote.modifiedAt, order: .reverse)
private var notes: [SampleNote]
// Insert/update/delete
modelContext.insert(newNote)
existingNote.updateContent(title: "Updated")
modelContext.delete(note)Example: Notes feature with full CRUD
Use for: Structured app data, user content, complex queries
Pro: Type-safe, SwiftUI integration, automatic CloudKit sync
Con: iOS 17+ / macOS 14+ only
Why SwiftData?
- Zero boilerplate: No NSManagedObject subclassing or Core Data stack setup
- Type safety: Swift macros generate all persistence code at compile time
- Modern patterns: Built for Swift 6 concurrency from the ground up
- SwiftUI native:
@Queryproperty wrapper updates views automatically - iCloud sync: One line of code enables CloudKit sync across devices
- Better DX: Errors at compile time, not runtime
See SampleNote, NotesListView, and NoteEditorView for complete
implementation.
Error Handling:
public enum YourError: Error, Sendable {
case networkError
case invalidData
}
public func fetchData() async throws(YourError) {
// Implementation
}A minimal but complete app demonstrating essential patterns:
Marketing View:
- Beautiful landing page showcasing FoldingKit features
- Cross-platform layout (iOS and macOS)
- SF Symbols 6 animations
- Navigation to Settings and Notes
Notes Feature (SwiftData):
- Full CRUD - Create, read, update, delete notes
- Rich data model - Title, content, tags, timestamps
- Modern UI - Empty state, list view, editor sheet
- SwiftData queries - Sorted by modified date
- iCloud sync ready - Automatic CloudKit integration
- Perfect example of modern Apple platform data persistence
Settings View (3 Legacy Storage Patterns):
- UserDefaults - Dark mode preference (local only)
- iCloud Key-Value Store - Sample feature toggle (syncs across devices)
- Keychain - Private data storage (encrypted, syncs via iCloud Keychain)
- Card-based layout with dividers
- Professional typography
Navigation:
- iOS: Drawer pattern with swipe gestures and animations
- macOS: Sidebar navigation with hover effects
- SF Symbols 6 bounce animations on click
- Adaptive layouts for each platform
Development Tools:
- Automatic code formatting (SwiftFormat)
- Automatic linting (SwiftLint)
- Git hooks (pre-commit + commit-msg)
- Conventional commits enforced
- Auto-generated changelog from commits
- Makefile with common commands
Just 35 files total (24 source + 11 tests), focused on demonstrating patterns you can build upon.
Native macOS app with:
- Sidebar navigation
- Keyboard shortcuts (Cmd+N, Cmd+,)
- Right-click context menus
- Resizable windows
- Menu bar integration
Enable in Xcode: Target → General → Supported Destinations → Add macOS (15.0+)
FoldingKit includes infrastructure stubs for common iOS/macOS app services. All code is commented out to avoid requiring certificates, backend configuration, or entitlements in the starter kit.
Push Notifications (NotificationManager.swift)
- Remote notifications from APNs
- Device token management
- Notification handling
- Fully commented with activation guide
Background Tasks (BackgroundTaskManager.swift)
- Periodic app refresh (short tasks)
- Background processing (long tasks)
- Task scheduling and handling
- Debugger testing support
Universal Links (DeepLinkManager.swift)
- Deep linking from web URLs
- Custom URL schemes
- Navigation integration
- URL parsing examples
Each service stub includes comprehensive inline documentation:
- Uncomment implementation - Remove
/* ... */blocks - Add capabilities - Enable in Xcode project settings
- Configure entitlements - Add required permissions
- Test integration - Follow testing guides
See docs/how-to/APP_SERVICES.md for detailed activation guides, security
considerations, and troubleshooting.
Philosophy: Services are disabled by default. Enable only what your app needs.
- How-To Guides:
docs/how-to/- Implementation guides (app services, etc.) - AI Development:
docs/ai-dev/- AI-assisted development planning and history - AI Guidelines:
.cursor/rules/- Development patterns and best practices
Documentation Conventions:
- Active AI development docs live in
docs/ai-dev/ - Completed AI development docs move to
docs/ai-dev/completed/when done - How-to guides for features live in
docs/how-to/ - Use descriptive names without project prefix
- Status progression: Planning → In Progress → Complete (move to completed/)
- Makefile - Build, test, lint, format, release commands
- Git Hooks - Pre-commit formatting and commit message validation
- Changelog - Auto-generated from conventional commits (
.chglog/) - Scripts - Automation in
scripts/directory
- Test Plan:
FoldingKit.xctestplan- Xcode test configuration - Unit Tests:
Tests/- Core logic with mocks and helpers - UI Tests:
UITests/(iOS) +MacOSUITests/(macOS) with base test cases
MIT License - See LICENSE file
Transform this starter kit into your next iOS and macOS app. 🚀