Initial commit
This commit is contained in:
55
skills/ios-swift-expert/references/apple-guidelines.md
Normal file
55
skills/ios-swift-expert/references/apple-guidelines.md
Normal file
@@ -0,0 +1,55 @@
|
||||
# Apple Guidelines & Resources
|
||||
|
||||
Authoritative sources for iOS and macOS development best practices.
|
||||
|
||||
## Official Documentation
|
||||
|
||||
- **Apple Developer Documentation**: https://developer.apple.com/documentation/
|
||||
- **Swift Language Guide**: https://docs.swift.org/swift-book/
|
||||
- **Human Interface Guidelines**: https://developer.apple.com/design/human-interface-guidelines/
|
||||
- **Swift API Design Guidelines**: https://www.swift.org/documentation/api-design-guidelines/
|
||||
- **WWDC Videos**: https://developer.apple.com/videos/
|
||||
|
||||
## Human Interface Guidelines
|
||||
|
||||
Follow platform conventions for:
|
||||
- Navigation patterns and controls
|
||||
- Interactions and gestures
|
||||
- Dynamic Type for accessibility
|
||||
- Privacy preferences handling
|
||||
- Multitasking and background modes
|
||||
|
||||
## Swift API Design Guidelines
|
||||
|
||||
Key principles:
|
||||
- Clarity at the point of use
|
||||
- Naming that makes code read like prose
|
||||
- Prefer methods and properties over free functions
|
||||
- Omit needless words
|
||||
- Compensate for weak type information
|
||||
|
||||
## Privacy & Security
|
||||
|
||||
Best practices:
|
||||
- Request permissions with clear purpose strings
|
||||
- Handle user data securely (Keychain for credentials)
|
||||
- Use App Transport Security (HTTPS by default)
|
||||
- Implement Face ID/Touch ID for sensitive operations
|
||||
- Follow privacy manifests requirements (iOS 17+)
|
||||
|
||||
## Accessibility
|
||||
|
||||
Requirements:
|
||||
- Add accessibility labels and hints
|
||||
- Support VoiceOver navigation
|
||||
- Test with Accessibility Inspector
|
||||
- Support Dynamic Type and larger text sizes
|
||||
- Ensure sufficient color contrast
|
||||
|
||||
## Localization
|
||||
|
||||
Guidelines:
|
||||
- Use `NSLocalizedString` for user-facing text
|
||||
- Support right-to-left languages
|
||||
- Externalize date/number formatting
|
||||
- Test with pseudo-localization
|
||||
153
skills/ios-swift-expert/references/code-examples.md
Normal file
153
skills/ios-swift-expert/references/code-examples.md
Normal file
@@ -0,0 +1,153 @@
|
||||
# iOS Development Code Examples
|
||||
|
||||
Complete implementation examples for common iOS and macOS development patterns.
|
||||
|
||||
## SwiftUI View with Proper State Management
|
||||
|
||||
```swift
|
||||
import SwiftUI
|
||||
|
||||
struct UserProfileView: View {
|
||||
@StateObject private var viewModel = UserProfileViewModel()
|
||||
@Environment(\.dismiss) private var dismiss
|
||||
|
||||
var body: some View {
|
||||
NavigationStack {
|
||||
ScrollView {
|
||||
VStack(alignment: .leading, spacing: 16) {
|
||||
// Profile content
|
||||
AsyncImage(url: viewModel.avatarURL) { image in
|
||||
image
|
||||
.resizable()
|
||||
.scaledToFill()
|
||||
} placeholder: {
|
||||
ProgressView()
|
||||
}
|
||||
.frame(width: 100, height: 100)
|
||||
.clipShape(Circle())
|
||||
|
||||
Text(viewModel.userName)
|
||||
.font(.title)
|
||||
.accessibilityAddTraits(.isHeader)
|
||||
}
|
||||
.padding()
|
||||
}
|
||||
.navigationTitle("Profile")
|
||||
.toolbar {
|
||||
ToolbarItem(placement: .navigationBarTrailing) {
|
||||
Button("Done") {
|
||||
dismiss()
|
||||
}
|
||||
}
|
||||
}
|
||||
.task {
|
||||
await viewModel.loadProfile()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## MVVM ViewModel with Async/Await
|
||||
|
||||
```swift
|
||||
import Foundation
|
||||
import Combine
|
||||
|
||||
@MainActor
|
||||
final class UserProfileViewModel: ObservableObject {
|
||||
@Published private(set) var userName: String = ""
|
||||
@Published private(set) var avatarURL: URL?
|
||||
@Published private(set) var isLoading = false
|
||||
@Published private(set) var error: Error?
|
||||
|
||||
private let userService: UserServiceProtocol
|
||||
|
||||
init(userService: UserServiceProtocol = UserService()) {
|
||||
self.userService = userService
|
||||
}
|
||||
|
||||
func loadProfile() async {
|
||||
isLoading = true
|
||||
error = nil
|
||||
|
||||
do {
|
||||
let profile = try await userService.fetchCurrentUser()
|
||||
userName = profile.name
|
||||
avatarURL = profile.avatarURL
|
||||
} catch {
|
||||
self.error = error
|
||||
}
|
||||
|
||||
isLoading = false
|
||||
}
|
||||
}
|
||||
|
||||
// Protocol for dependency injection and testing
|
||||
protocol UserServiceProtocol {
|
||||
func fetchCurrentUser() async throws -> UserProfile
|
||||
}
|
||||
```
|
||||
|
||||
## Core Data Stack with Modern Concurrency
|
||||
|
||||
```swift
|
||||
import CoreData
|
||||
|
||||
final class PersistenceController {
|
||||
static let shared = PersistenceController()
|
||||
|
||||
let container: NSPersistentContainer
|
||||
|
||||
private init() {
|
||||
container = NSPersistentContainer(name: "AppModel")
|
||||
container.loadPersistentStores { description, error in
|
||||
if let error = error {
|
||||
fatalError("Unable to load persistent stores: \(error)")
|
||||
}
|
||||
}
|
||||
container.viewContext.automaticallyMergesChangesFromParent = true
|
||||
}
|
||||
|
||||
func save() async throws {
|
||||
let context = container.viewContext
|
||||
guard context.hasChanges else { return }
|
||||
|
||||
try await context.perform {
|
||||
try context.save()
|
||||
}
|
||||
}
|
||||
|
||||
func backgroundContext() -> NSManagedObjectContext {
|
||||
let context = container.newBackgroundContext()
|
||||
context.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy
|
||||
return context
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Proper Memory Management with Closures
|
||||
|
||||
```swift
|
||||
import UIKit
|
||||
|
||||
final class DataManager {
|
||||
private var completionHandlers: [String: (Result<Data, Error>) -> Void] = [:]
|
||||
|
||||
func fetchData(forKey key: String, completion: @escaping (Result<Data, Error>) -> Void) {
|
||||
completionHandlers[key] = completion
|
||||
|
||||
URLSession.shared.dataTask(with: URL(string: "https://example.com")!) { [weak self] data, response, error in
|
||||
guard let self = self else { return }
|
||||
|
||||
if let error = error {
|
||||
self.completionHandlers[key]?(.failure(error))
|
||||
} else if let data = data {
|
||||
self.completionHandlers[key]?(.success(data))
|
||||
}
|
||||
|
||||
self.completionHandlers[key] = nil
|
||||
}.resume()
|
||||
}
|
||||
}
|
||||
```
|
||||
26
skills/ios-swift-expert/references/debugging-strategies.md
Normal file
26
skills/ios-swift-expert/references/debugging-strategies.md
Normal file
@@ -0,0 +1,26 @@
|
||||
# Debugging Strategies
|
||||
|
||||
Comprehensive debugging techniques for iOS and macOS development.
|
||||
|
||||
## Xcode Build Issues
|
||||
|
||||
1. **Clean Build Folder**: Product → Clean Build Folder (Cmd+Shift+K)
|
||||
2. **Delete Derived Data**: `rm -rf ~/Library/Developer/Xcode/DerivedData`
|
||||
3. **Check Build Settings**: Verify code signing, Swift version, deployment target
|
||||
4. **Read Error Carefully**: Xcode errors often include fix-its
|
||||
5. **Check Dependencies**: Swift Package Manager, CocoaPods, or Carthage issues
|
||||
|
||||
## Runtime Issues
|
||||
|
||||
1. **Breakpoints**: Set symbolic breakpoints for exceptions
|
||||
2. **LLDB Commands**: `po`, `expr`, `frame variable` for inspection
|
||||
3. **View Debugging**: Use Xcode's visual debugger (Debug → View Debugging)
|
||||
4. **Memory Graph**: Detect retain cycles with Debug → Memory Graph
|
||||
5. **Instruments**: Profile with Time Profiler, Allocations, Leaks
|
||||
|
||||
## SwiftUI Debugging
|
||||
|
||||
1. **Preview Crashes**: Check `PreviewProvider` initialization
|
||||
2. **State Updates**: Verify state changes on main thread
|
||||
3. **View Redrawing**: Use `Self._printChanges()` to debug updates
|
||||
4. **Modifiers Order**: Order matters (frame before padding vs. padding before frame)
|
||||
78
skills/ios-swift-expert/references/patterns.md
Normal file
78
skills/ios-swift-expert/references/patterns.md
Normal file
@@ -0,0 +1,78 @@
|
||||
# Common Patterns & Solutions
|
||||
|
||||
Design patterns and solutions for iOS and macOS development.
|
||||
|
||||
## Pattern: Dependency Injection
|
||||
|
||||
**Problem:** Tight coupling makes testing difficult
|
||||
**Solution:** Use protocol-based dependency injection
|
||||
|
||||
```swift
|
||||
protocol NetworkServiceProtocol {
|
||||
func fetch<T: Decodable>(_ endpoint: Endpoint) async throws -> T
|
||||
}
|
||||
|
||||
struct ContentView: View {
|
||||
@StateObject private var viewModel: ContentViewModel
|
||||
|
||||
init(networkService: NetworkServiceProtocol = NetworkService()) {
|
||||
_viewModel = StateObject(wrappedValue: ContentViewModel(networkService: networkService))
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
// View implementation
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Pattern: Result Builders
|
||||
|
||||
**Problem:** Complex view hierarchies
|
||||
**Solution:** Use result builders for DSL-like syntax
|
||||
|
||||
```swift
|
||||
@resultBuilder
|
||||
struct ViewArrayBuilder {
|
||||
static func buildBlock(_ components: [AnyView]...) -> [AnyView] {
|
||||
components.flatMap { $0 }
|
||||
}
|
||||
|
||||
static func buildExpression<V: View>(_ expression: V) -> [AnyView] {
|
||||
[AnyView(expression)]
|
||||
}
|
||||
}
|
||||
|
||||
func createViews(@ViewArrayBuilder _ builder: () -> [AnyView]) -> [AnyView] {
|
||||
builder()
|
||||
}
|
||||
```
|
||||
|
||||
## Pattern: Coordinator for Navigation
|
||||
|
||||
**Problem:** Complex navigation logic scattered across views
|
||||
**Solution:** Centralize navigation in coordinator
|
||||
|
||||
```swift
|
||||
@MainActor
|
||||
final class AppCoordinator: ObservableObject {
|
||||
@Published var path = NavigationPath()
|
||||
|
||||
enum Route: Hashable {
|
||||
case detail(id: String)
|
||||
case settings
|
||||
case profile
|
||||
}
|
||||
|
||||
func navigate(to route: Route) {
|
||||
path.append(route)
|
||||
}
|
||||
|
||||
func pop() {
|
||||
path.removeLast()
|
||||
}
|
||||
|
||||
func popToRoot() {
|
||||
path = NavigationPath()
|
||||
}
|
||||
}
|
||||
```
|
||||
Reference in New Issue
Block a user