Skip to content

Commit 61f8d57

Browse files
committed
Updated readme
1 parent b499ba4 commit 61f8d57

File tree

2 files changed

+198
-55
lines changed

2 files changed

+198
-55
lines changed

ChatGTP.md

Lines changed: 0 additions & 24 deletions
This file was deleted.

README.md

Lines changed: 198 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -6,83 +6,250 @@
66

77
## Overview
88

9-
Footprint is a Swift library that helps manage and monitor memory usage in your app. It provides a flexible approach to handling memory levels, allowing you to adapt your app's behavior based on the available memory and potential termination risks.
9+
Footprint is a Swift library that provides proactive memory management for your Apple platform apps. Instead of waiting for memory warnings that come too late, Footprint gives you real-time insights into your app's memory usage and proximity to termination, allowing you to adapt your app's behavior dynamically.
1010

11-
### Key Features
11+
### The Problem
1212

13-
- **Memory State Management:** Footprint categorizes memory states into normal, warning, critical, and terminal, providing insights into your app's proximity to termination due to memory constraints.
13+
Traditional memory management on Apple platforms relies on memory warnings that often arrive too late, especially for larger apps. While `os_proc_available_memory` tells you how much memory remains, you still lack the complete picture of your memory boundaries and usage patterns.
1414

15-
- **Dynamic Memory Handling:** Change your app's behavior dynamically based on the current memory state. For instance, adjust cache sizes or optimize resource usage to enhance performance.
15+
### The Solution
1616

17-
- **SwiftUI Integration:** Easily observe and respond to changes in the app's memory state within SwiftUI views using the `onFootprintMemoryStateDidChange` modifier.
17+
Footprint bridges this gap by providing:
18+
- **Complete memory visibility**: Track used, remaining, and total memory limits
19+
- **Proactive state management**: Five distinct memory states from normal to terminal
20+
- **Behavioral adaptation**: Change your app's behavior before hitting critical memory limits
21+
- **Multiple observation patterns**: NotificationCenter, async streams, and SwiftUI modifiers
22+
23+
## Key Features
24+
25+
- **Five Memory States**: Navigate through normal, warning, urgent, critical, and terminal states based on memory usage ratios
26+
- **Dual Tracking**: Monitor both memory footprint and system memory pressure
27+
- **Real-time Monitoring**: 500ms heartbeat with smart change detection
28+
- **SwiftUI Integration**: Convenient view modifiers for reactive UI updates
29+
- **Async Support**: Modern async/await patterns with AsyncStream
30+
- **Cross-platform**: Works on iOS, macOS, tvOS, watchOS, and visionOS
1831

1932
## Installation
2033

21-
Add the Footprint library to your project:
34+
Add Footprint to your project using Swift Package Manager:
2235

23-
1. In Xcode, with your app project open, navigate to File > Add Packages.
24-
2. When prompted, add the Firebase Apple platforms SDK repository:
36+
1. In Xcode, navigate to File > Add Package Dependencies
37+
2. Enter the repository URL:
2538
```
2639
https://github.com/naftaly/Footprint
2740
```
2841

2942
## Usage
3043

31-
### Initialization
44+
### Basic Setup
3245

33-
Initialize Footprint as early as possible in your app's lifecycle:
46+
Initialize Footprint early in your app's lifecycle. The shared instance automatically begins monitoring:
3447

3548
```swift
49+
// Start monitoring (typically in your App or AppDelegate)
3650
let _ = Footprint.shared
3751
```
3852

3953
### Memory State Observation
4054

41-
Respond to changes in memory state using the provided notification:
55+
#### Using NotificationCenter
56+
57+
```swift
58+
NotificationCenter.default.addObserver(
59+
forName: Footprint.memoryDidChangeNotification,
60+
object: nil,
61+
queue: nil
62+
) { notification in
63+
guard let newMemory = notification.userInfo?[Footprint.newMemoryKey] as? Footprint.Memory,
64+
let oldMemory = notification.userInfo?[Footprint.oldMemoryKey] as? Footprint.Memory,
65+
let changes = notification.userInfo?[Footprint.changesKey] as? Set<Footprint.ChangeType>
66+
else { return }
67+
68+
if changes.contains(.state) {
69+
print("Memory state changed from \(oldMemory.state) to \(newMemory.state)")
70+
adaptBehavior(for: newMemory.state)
71+
}
72+
}
73+
```
74+
75+
#### Using Closures
4276

4377
```swift
44-
NotificationCenter.default.addObserver(forName: Footprint.stateDidChangeNotification, object: nil, queue: nil) { notification in
45-
if let newState = notification.userInfo?[Footprint.newMemoryStateKey] as? Footprint.Memory.State,
46-
let oldState = notification.userInfo?[Footprint.oldMemoryStateKey] as? Footprint.Memory.State {
47-
print("Memory state changed from \(oldState) to \(newState)")
48-
// Perform actions based on the memory state change
78+
Footprint.shared.observe { memory in
79+
print("Current memory state: \(memory.state)")
80+
print("Used: \(ByteCountFormatter.string(fromByteCount: memory.used, countStyle: .memory))")
81+
print("Remaining: \(ByteCountFormatter.string(fromByteCount: memory.remaining, countStyle: .memory))")
82+
}
83+
```
84+
85+
#### Using Async Streams
86+
87+
```swift
88+
Task {
89+
for await memory in Footprint.shared.memoryStream {
90+
await handleMemoryChange(memory)
4991
}
5092
}
5193
```
5294

5395
### SwiftUI Integration
5496

55-
Use the SwiftUI extension to observe changes in memory state within your views:
97+
#### Comprehensive Memory Changes
98+
99+
```swift
100+
Text("Memory Status: \(memoryState)")
101+
.onFootprintMemoryDidChange { newMemory, oldMemory, changes in
102+
if changes.contains(.state) {
103+
updateCachePolicy(for: newMemory.state)
104+
}
105+
if changes.contains(.pressure) {
106+
handleMemoryPressure(newMemory.pressure)
107+
}
108+
}
109+
```
110+
111+
#### State-Specific Changes
56112

57113
```swift
58-
Text("Hello, World!")
114+
MyView()
59115
.onFootprintMemoryStateDidChange { newState, oldState in
60-
print("Memory state changed from \(oldState) to \(newState)")
61-
// Perform actions based on the memory state change
116+
switch newState {
117+
case .normal:
118+
enableFullFeatures()
119+
case .warning:
120+
reduceCacheSize(by: 0.2)
121+
case .urgent:
122+
reduceCacheSize(by: 0.5)
123+
case .critical:
124+
clearNonEssentialCaches()
125+
case .terminal:
126+
emergencyMemoryCleanup()
127+
}
128+
}
129+
```
130+
131+
#### Pressure-Specific Changes
132+
133+
```swift
134+
ContentView()
135+
.onFootprintMemoryPressureDidChange { newPressure, oldPressure in
136+
handleSystemMemoryPressure(newPressure)
62137
}
63138
```
64139

65-
### Memory Information Retrieval
140+
### Memory Information
66141

67-
Retrieve current memory information:
142+
Access current memory state and information:
68143

69144
```swift
70-
let currentMemory = footprint.memory
71-
print("Used Memory: \(currentMemory.used) bytes")
72-
print("Remaining Memory: \(currentMemory.remaining) bytes")
73-
print("Memory Limit: \(currentMemory.limit) bytes")
74-
print("Memory State: \(currentMemory.state)")
145+
let memory = Footprint.shared.memory
146+
147+
print("Used: \(memory.used) bytes")
148+
print("Remaining: \(memory.remaining) bytes")
149+
print("Limit: \(memory.limit) bytes")
150+
print("State: \(memory.state)")
151+
print("Pressure: \(memory.pressure)")
152+
print("Timestamp: \(memory.timestamp)")
75153
```
76154

77-
### Memory Allocation Check
155+
### Memory Allocation Planning
78156

79-
Check if a certain amount of memory can be allocated:
157+
Check if memory allocation is likely to succeed:
80158

81159
```swift
82-
let canAllocate = footprint.canAllocate(bytes: 1024)
83-
print("Can allocate 1KB: \(canAllocate)")
160+
let sizeNeeded: UInt64 = 50_000_000 // 50MB
161+
if Footprint.shared.canAllocate(bytes: sizeNeeded) {
162+
// Proceed with allocation
163+
performMemoryIntensiveOperation()
164+
} else {
165+
// Consider alternatives or cleanup
166+
cleanupBeforeAllocation()
167+
}
84168
```
85169

170+
## Memory States Explained
171+
172+
Footprint categorizes memory usage into five states based on the ratio of used memory to total limit:
173+
174+
- **Normal** (< 25%): Full functionality, optimal performance
175+
- **Warning** (25-50%): Begin reducing memory usage, optimize caches
176+
- **Urgent** (50-75%): Significant memory reduction needed
177+
- **Critical** (75-90%): Aggressive cleanup required
178+
- **Terminal** (> 90%): Imminent termination risk, emergency measures
179+
180+
## Practical Examples
181+
182+
### Adaptive Cache Management
183+
184+
```swift
185+
class ImageCache {
186+
private var maxCost: Int = 100_000_000 // 100MB default
187+
188+
init() {
189+
Footprint.shared.observe { [weak self] memory in
190+
self?.adjustCacheSize(for: memory.state)
191+
}
192+
}
193+
194+
private func adjustCacheSize(for state: Footprint.Memory.State) {
195+
let multiplier: Double = switch state {
196+
case .normal: 1.0
197+
case .warning: 0.8
198+
case .urgent: 0.5
199+
case .critical: 0.2
200+
case .terminal: 0.0
201+
}
202+
203+
cache.totalCostLimit = Int(Double(maxCost) * multiplier)
204+
}
205+
}
206+
```
207+
208+
### Conditional Feature Loading
209+
210+
```swift
211+
func loadOptionalFeatures() {
212+
let currentState = Footprint.shared.state
213+
214+
guard currentState < .urgent else {
215+
// Skip non-essential features in high memory usage
216+
return
217+
}
218+
219+
enableAdvancedAnimations()
220+
preloadAdditionalContent()
221+
}
222+
```
223+
224+
## Development and Testing
225+
226+
### Simulator Support
227+
228+
Footprint includes simulator-specific handling since memory limits work differently. You can enable simulated termination for testing:
229+
230+
```bash
231+
# Enable simulated out-of-memory termination in simulator
232+
export SIM_FOOTPRINT_OOM_TERM_ENABLED=1
233+
```
234+
235+
### Custom Memory Providers
236+
237+
For testing or custom scenarios, implement the `MemoryProvider` protocol:
238+
239+
```swift
240+
class MockMemoryProvider: MemoryProvider {
241+
func provide(_ pressure: Footprint.Memory.State) -> Footprint.Memory {
242+
// Return custom memory values for testing
243+
}
244+
}
245+
```
246+
247+
## Requirements
248+
249+
- iOS 13.0+, macOS 10.15+, tvOS 13.0+, watchOS 6.0+, visionOS 1.0+
250+
- Swift 5.0+
251+
- Xcode 11.0+
252+
86253
## License
87254

88255
Footprint is available under the MIT license. See the [LICENSE](LICENSE) file for more info.

0 commit comments

Comments
 (0)