Files
2026-04-12 01:06:31 +07:00

497 lines
10 KiB
Markdown

# iOS Native Development
Complete guide to iOS development with Swift and SwiftUI (2024-2025).
## Swift 6 Overview
### Key Features
- **Data race safety**: Compile-time detection (default in Swift 6)
- **Concurrency**: async/await, actors, @MainActor
- **Macro system**: Code generation at compile time
- **Move semantics**: Ownership optimization
- **Enhanced generics**: More powerful type system
### Modern Swift Patterns
**Async/Await:**
```swift
func fetchUser(id: String) async throws -> User {
let (data, _) = try await URLSession.shared.data(from: url)
return try JSONDecoder().decode(User.self, from: data)
}
// Usage
Task {
do {
let user = try await fetchUser(id: "123")
self.user = user
} catch {
self.error = error
}
}
```
**Actors (Thread-safe classes):**
```swift
actor UserCache {
private var cache: [String: User] = [:]
func get(_ id: String) -> User? {
cache[id]
}
func set(_ id: String, user: User) {
cache[id] = user
}
}
```
## SwiftUI vs UIKit
### When to Use SwiftUI
✅ New projects (iOS 13+)
✅ Declarative UI preferred
✅ Fast iteration needed
✅ Cross-platform (macOS, watchOS, tvOS)
✅ 40% less code vs UIKit
### When to Use UIKit
✅ Legacy app maintenance
✅ Complex customizations
✅ Fine-grained control needed
✅ Specific UIKit features required
✅ Pre-iOS 13 support
### SwiftUI Basics
```swift
struct ContentView: View {
@State private var count = 0
var body: some View {
VStack(spacing: 20) {
Text("Count: \(count)")
.font(.title)
Button("Increment") {
count += 1
}
.buttonStyle(.borderedProminent)
}
.padding()
}
}
```
**Property Wrappers:**
- `@State`: View-local state
- `@Binding`: Two-way binding
- `@StateObject`: Observable object owner
- `@ObservedObject`: Observable object reference
- `@EnvironmentObject`: Dependency injection
- `@Published`: Observable property
## Architecture Patterns
### MVVM (Most Popular)
```swift
// Model
struct User: Identifiable, Codable {
let id: String
let name: String
let email: String
}
// ViewModel
@MainActor
class UserViewModel: ObservableObject {
@Published var users: [User] = []
@Published var isLoading = false
@Published var error: Error?
private let repository: UserRepository
init(repository: UserRepository = UserRepository()) {
self.repository = repository
}
func loadUsers() async {
isLoading = true
defer { isLoading = false }
do {
users = try await repository.fetchUsers()
} catch {
self.error = error
}
}
}
// View
struct UserListView: View {
@StateObject private var viewModel = UserViewModel()
var body: some View {
List(viewModel.users) { user in
Text(user.name)
}
.task {
await viewModel.loadUsers()
}
}
}
```
### TCA (The Composable Architecture)
**When to use:**
- Complex state management
- Predictable state updates
- Excellent testing
- Enterprise apps
**Trade-offs:**
- Steeper learning curve
- More boilerplate
- Excellent for large teams
## Performance Optimization
### Compiler Optimizations
**1. Use `final` classes:**
```swift
final class FastClass {
// Compiler can optimize (no dynamic dispatch)
}
```
**2. Private methods:**
```swift
private func optimize() {
// Compiler can inline
}
```
**3. Whole-module optimization:**
```bash
# Build Settings
SWIFT_WHOLE_MODULE_OPTIMIZATION = YES
```
### Memory Management
**ARC (Automatic Reference Counting):**
```swift
class Parent {
var child: Child?
}
class Child {
weak var parent: Parent? // Weak to avoid retain cycle
}
```
**Common Retain Cycles:**
```swift
// ❌ Bad: Retain cycle
class ViewController: UIViewController {
var completion: (() -> Void)?
func setup() {
completion = {
self.doSomething() // Strong capture
}
}
}
// ✅ Good: Weak self
class ViewController: UIViewController {
var completion: (() -> Void)?
func setup() {
completion = { [weak self] in
self?.doSomething()
}
}
}
```
### SwiftUI Performance
**1. Use const modifiers:**
```swift
Text("Hello") // Recreated on every render
vs
Text("Hello")
.font(.title) // Modifier creates new view
// Better: Extract static views
let titleText = Text("Hello").font(.title)
```
**2. Avoid expensive computations:**
```swift
struct ExpensiveView: View {
let data: [Item]
// Computed every render
var sortedData: [Item] {
data.sorted() // ❌ Bad
}
// Better: Cache with @State or pass sorted
}
```
## Testing Strategies
### XCTest (Unit Testing)
```swift
import XCTest
@testable import MyApp
final class UserViewModelTests: XCTestCase {
var viewModel: UserViewModel!
var mockRepository: MockUserRepository!
override func setUp() {
super.setUp()
mockRepository = MockUserRepository()
viewModel = UserViewModel(repository: mockRepository)
}
func testLoadUsers() async throws {
// Given
let expectedUsers = [User(id: "1", name: "Test", email: "test@example.com")]
mockRepository.usersToReturn = expectedUsers
// When
await viewModel.loadUsers()
// Then
XCTAssertEqual(viewModel.users, expectedUsers)
XCTAssertFalse(viewModel.isLoading)
XCTAssertNil(viewModel.error)
}
}
```
### XCUITest (UI Testing)
```swift
import XCTest
final class LoginUITests: XCTestCase {
let app = XCUIApplication()
override func setUp() {
super.setUp()
app.launch()
}
func testLoginFlow() {
let emailField = app.textFields["emailField"]
emailField.tap()
emailField.typeText("test@example.com")
let passwordField = app.secureTextFields["passwordField"]
passwordField.tap()
passwordField.typeText("password123")
app.buttons["loginButton"].tap()
XCTAssertTrue(app.staticTexts["Welcome"].waitForExistence(timeout: 5))
}
}
```
**Target Coverage:**
- Unit tests: 70-80%+
- Critical paths: 100%
- UI tests: Key user flows only (slow)
## iOS-Specific Features
### WidgetKit
```swift
import WidgetKit
import SwiftUI
struct SimpleWidget: Widget {
var body: some WidgetConfiguration {
StaticConfiguration(kind: "SimpleWidget", provider: Provider()) { entry in
SimpleWidgetView(entry: entry)
}
.configurationDisplayName("My Widget")
.description("This is my widget")
.supportedFamilies([.systemSmall, .systemMedium, .systemLarge])
}
}
```
### Live Activities (iOS 16.1+)
```swift
import ActivityKit
struct OrderAttributes: ActivityAttributes {
struct ContentState: Codable, Hashable {
var status: String
var estimatedTime: Date
}
var orderId: String
}
// Start activity
let attributes = OrderAttributes(orderId: "123")
let initialState = OrderAttributes.ContentState(
status: "Preparing",
estimatedTime: Date().addingTimeInterval(1800)
)
let activity = try Activity.request(
attributes: attributes,
contentState: initialState
)
```
### App Clips
**Characteristics:**
- <10MB size limit
- Fast, lightweight experiences
- No installation required
- Invoked via NFC, QR, Safari, Maps
## Human Interface Guidelines (HIG)
### Navigation Patterns
**Tab Bar:**
- 2-5 top-level sections
- Bottom placement
- Always visible
- Immediate navigation
**Navigation Bar:**
- Hierarchical navigation
- Back button automatic
- Title and actions
- Large/inline title modes
**Modal Presentation:**
- Interrupting tasks
- Self-contained flow
- Clear dismiss action
- Use sparingly
### Design Principles
**Clarity:**
- Legible text (minimum 11pt)
- Sufficient contrast (WCAG AA)
- Precise icons
**Deference:**
- Content first, UI second
- Translucent backgrounds
- Minimal UI elements
**Depth:**
- Layering (sheets, overlays)
- Visual hierarchy
- Motion provides meaning
### Colors
**System Colors:**
```swift
Color.primary // Adaptive black/white
Color.secondary // Gray
Color.accentColor // App tint color
Color(uiColor: .systemBlue)
Color(uiColor: .label)
```
**Dark Mode:**
```swift
// Automatic
Color.primary // Adapts to light/dark
// Custom
Color("CustomColor") // Define in Assets.xcassets
```
### SF Symbols
```swift
Image(systemName: "star.fill")
.foregroundColor(.yellow)
.font(.title)
// Rendering modes
Image(systemName: "heart.fill")
.symbolRenderingMode(.multicolor)
```
## App Store Requirements (2024-2025)
### SDK Requirements
- **Current**: Xcode 15+ with iOS 17 SDK (required as of April 2024)
- **Upcoming**: Xcode 16+ with iOS 18 SDK (recommended for 2025 submissions)
### Privacy
- **Privacy manifest**: Required for third-party SDKs
- **Tracking permission**: ATT framework for advertising
- **Privacy nutrition labels**: Accurate data collection info
- **Account deletion**: In-app deletion required
### Capabilities
- **Sandbox**: All apps sandboxed
- **Entitlements**: Request only needed capabilities
- **Background modes**: Justify background usage
- **HealthKit**: Privacy-sensitive, strict review
### Submission Checklist
App icons (all required sizes)
Screenshots (all device sizes)
App description and keywords
Privacy policy URL
Support URL
Age rating questionnaire
Export compliance
Test on real devices
No crashes or major bugs
## Common Pitfalls
1. **Strong reference cycles**: Use `[weak self]` in closures
2. **Main thread blocking**: Use async/await, avoid sync operations
3. **Large images**: Resize before displaying
4. **Unhandled errors**: Always handle async throws
5. **Ignoring safe areas**: Use `.ignoresSafeArea()` intentionally
6. **Not testing dark mode**: Design for both appearances
7. **Hardcoded strings**: Use localization from start
8. **Memory leaks**: Profile with Instruments regularly
## Resources
**Official:**
- Swift Documentation: https://swift.org/documentation/
- SwiftUI Tutorials: https://developer.apple.com/tutorials/swiftui
- HIG: https://developer.apple.com/design/human-interface-guidelines/
- WWDC Videos: https://developer.apple.com/videos/
**Community:**
- Hacking with Swift: https://www.hackingwithswift.com/
- Swift by Sundell: https://www.swiftbysundell.com/
- objc.io: https://www.objc.io/
- iOS Dev Weekly: https://iosdevweekly.com/