Files
daymade 4e3a54175e Release v1.18.0: Add iOS-APP-developer and promptfoo-evaluation skills
### Added
- **New Skill**: iOS-APP-developer v1.1.0 - iOS development with XcodeGen, SwiftUI, and SPM
  - XcodeGen project.yml configuration
  - SPM dependency resolution
  - Device deployment and code signing
  - Camera/AVFoundation debugging
  - iOS version compatibility handling
  - Library not loaded @rpath framework error fixes
  - State machine testing patterns for @MainActor classes
  - Bundled references: xcodegen-full.md, camera-avfoundation.md, swiftui-compatibility.md, testing-mainactor.md

- **New Skill**: promptfoo-evaluation v1.0.0 - LLM evaluation framework using Promptfoo
  - Promptfoo configuration (promptfooconfig.yaml)
  - Python custom assertions
  - llm-rubric for LLM-as-judge evaluations
  - Few-shot example management
  - Model comparison and prompt testing
  - Bundled reference: promptfoo_api.md

### Changed
- Updated marketplace version from 1.16.0 to 1.18.0
- Updated marketplace skills count from 23 to 25
- Updated skill-creator to v1.2.2:
  - Fixed best practices documentation URL (platform.claude.com)
  - Enhanced quick_validate.py to exclude file:// prefixed paths from validation
- Updated marketplace.json metadata description to include new skills

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-20 17:23:08 +08:00

3.6 KiB

SwiftUI iOS Version Compatibility

iOS 17 vs iOS 16 API Differences

View Modifiers

onChange

// iOS 17+ (dual parameter)
.onChange(of: value) { oldValue, newValue in
    // Can compare old and new
}

// iOS 16 (single parameter)
.onChange(of: value) { newValue in
    // Only new value available
}

sensoryFeedback (iOS 17+)

// iOS 17+
.sensoryFeedback(.impact, trigger: triggerValue)

// iOS 16 fallback
UIImpactFeedbackGenerator(style: .medium).impactOccurred()

Views

ContentUnavailableView (iOS 17+)

// iOS 17+
ContentUnavailableView(
    "No Results",
    systemImage: "magnifyingglass",
    description: Text("Try a different search")
)

// iOS 16 fallback
VStack(spacing: 16) {
    Image(systemName: "magnifyingglass")
        .font(.system(size: 48))
        .foregroundStyle(.secondary)
    Text("No Results")
        .font(.title2.bold())
    Text("Try a different search")
        .font(.subheadline)
        .foregroundStyle(.secondary)
}
.frame(maxWidth: .infinity, maxHeight: .infinity)

Inspector (iOS 17+)

// iOS 17+
.inspector(isPresented: $showInspector) {
    InspectorContent()
}

// iOS 16 fallback: Use sheet or sidebar
.sheet(isPresented: $showInspector) {
    InspectorContent()
}

Observation

@Observable Macro (iOS 17+)

// iOS 17+ with @Observable
@Observable
class ViewModel {
    var count = 0
}

struct ContentView: View {
    var viewModel = ViewModel()
    var body: some View {
        Text("\(viewModel.count)")
    }
}

// iOS 16 with ObservableObject
class ViewModel: ObservableObject {
    @Published var count = 0
}

struct ContentView: View {
    @StateObject var viewModel = ViewModel()
    var body: some View {
        Text("\(viewModel.count)")
    }
}

Audio

AVAudioApplication (iOS 17+)

// iOS 17+
let permission = AVAudioApplication.shared.recordPermission
AVAudioApplication.requestRecordPermission { granted in }

// iOS 16
let permission = AVAudioSession.sharedInstance().recordPermission
AVAudioSession.sharedInstance().requestRecordPermission { granted in }

Animations

Symbol Effects (iOS 17+)

// iOS 17+
Image(systemName: "heart.fill")
    .symbolEffect(.bounce, value: isFavorite)

// iOS 16 fallback
Image(systemName: "heart.fill")
    .scaleEffect(isFavorite ? 1.2 : 1.0)
    .animation(.spring(), value: isFavorite)

Data

SwiftData (iOS 17+)

// iOS 17+ with SwiftData
@Model
class Item {
    var name: String
    var timestamp: Date
}

// iOS 16: Use CoreData or third-party (Realm)
// CoreData: NSManagedObject subclass
// Realm: Object subclass with @Persisted properties

Conditional Compilation

For features that must use iOS 17 APIs when available:

if #available(iOS 17.0, *) {
    ContentUnavailableView("Title", systemImage: "icon")
} else {
    LegacyEmptyView()
}

For view modifiers:

extension View {
    @ViewBuilder
    func onChangeCompat<V: Equatable>(of value: V, perform: @escaping (V) -> Void) -> some View {
        if #available(iOS 17.0, *) {
            self.onChange(of: value) { _, newValue in
                perform(newValue)
            }
        } else {
            self.onChange(of: value, perform: perform)
        }
    }
}

Minimum Deployment Targets by Feature

Feature Minimum iOS
SwiftUI basics 13.0
@StateObject 14.0
AsyncImage 15.0
.searchable 15.0
NavigationStack 16.0
.navigationDestination 16.0
@Observable 17.0
ContentUnavailableView 17.0
SwiftData 17.0
.onChange (dual param) 17.0