@mmerterden/multi-agent-pipeline 20.7.0 → 20.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +9 -0
- package/LICENSE +0 -10
- package/docs/facts.json +1 -1
- package/manifest.json +266 -267
- package/package.json +2 -2
- package/pipeline/scripts/_notices.mjs +1 -1
- package/pipeline/skills/.skill-manifest.json +68 -68
- package/pipeline/skills/shared/README.md +70 -70
- package/pipeline/skills/shared/external/alarmkit/SKILL.md +373 -381
- package/pipeline/skills/shared/external/alarmkit/evals/evals.json +23 -18
- package/pipeline/skills/shared/external/alarmkit/references/alarmkit-patterns.md +328 -378
- package/pipeline/skills/shared/external/app-clips/SKILL.md +260 -160
- package/pipeline/skills/shared/external/app-clips/evals/evals.json +27 -27
- package/pipeline/skills/shared/external/app-clips/references/data-handoff-notifications-location.md +150 -83
- package/pipeline/skills/shared/external/app-clips/references/routing-and-experiences.md +135 -83
- package/pipeline/skills/shared/external/app-clips/references/size-capabilities-and-promotion.md +143 -85
- package/pipeline/skills/shared/external/app-intents/SKILL.md +302 -304
- package/pipeline/skills/shared/external/app-intents/evals/evals.json +21 -21
- package/pipeline/skills/shared/external/app-intents/references/appintents-advanced.md +594 -894
- package/pipeline/skills/shared/external/app-store-optimization/SKILL.md +339 -277
- package/pipeline/skills/shared/external/app-store-optimization/evals/evals.json +27 -23
- package/pipeline/skills/shared/external/app-store-optimization/references/keyword-research-methodology.md +105 -122
- package/pipeline/skills/shared/external/app-store-optimization/references/product-page-variants.md +143 -166
- package/pipeline/skills/shared/external/app-store-review/SKILL.md +307 -326
- package/pipeline/skills/shared/external/app-store-review/evals/evals.json +21 -21
- package/pipeline/skills/shared/external/app-store-review/references/privacy-manifest.md +105 -67
- package/pipeline/skills/shared/external/app-store-review/references/review-checklists.md +114 -101
- package/pipeline/skills/shared/external/apple-on-device-ai/SKILL.md +333 -360
- package/pipeline/skills/shared/external/apple-on-device-ai/evals/evals.json +24 -27
- package/pipeline/skills/shared/external/apple-on-device-ai/references/coreml-conversion.md +215 -322
- package/pipeline/skills/shared/external/apple-on-device-ai/references/coreml-optimization.md +161 -256
- package/pipeline/skills/shared/external/apple-on-device-ai/references/foundation-models.md +277 -387
- package/pipeline/skills/shared/external/apple-on-device-ai/references/mlx-swift.md +196 -210
- package/pipeline/skills/shared/external/authentication/SKILL.md +265 -381
- package/pipeline/skills/shared/external/authentication/evals/evals.json +25 -25
- package/pipeline/skills/shared/external/authentication/references/keychain-biometric.md +133 -178
- package/pipeline/skills/shared/external/authentication/references/passkeys.md +111 -147
- package/pipeline/skills/shared/external/avkit/SKILL.md +267 -364
- package/pipeline/skills/shared/external/avkit/evals/evals.json +26 -26
- package/pipeline/skills/shared/external/avkit/references/avkit-patterns.md +375 -493
- package/pipeline/skills/shared/external/background-processing/SKILL.md +270 -382
- package/pipeline/skills/shared/external/background-processing/evals/evals.json +22 -22
- package/pipeline/skills/shared/external/background-processing/references/background-task-patterns.md +169 -317
- package/pipeline/skills/shared/external/callkit-voip/SKILL.md +290 -371
- package/pipeline/skills/shared/external/callkit-voip/evals/evals.json +24 -24
- package/pipeline/skills/shared/external/callkit-voip/references/callkit-patterns.md +175 -343
- package/pipeline/skills/shared/external/cloudkit-sync/SKILL.md +292 -381
- package/pipeline/skills/shared/external/cloudkit-sync/evals/evals.json +33 -30
- package/pipeline/skills/shared/external/cloudkit-sync/references/cloudkit-patterns.md +227 -355
- package/pipeline/skills/shared/external/contacts-framework/SKILL.md +197 -346
- package/pipeline/skills/shared/external/contacts-framework/evals/evals.json +19 -21
- package/pipeline/skills/shared/external/contacts-framework/references/contacts-patterns.md +169 -308
- package/pipeline/skills/shared/external/core-bluetooth/SKILL.md +226 -376
- package/pipeline/skills/shared/external/core-bluetooth/evals/evals.json +25 -22
- package/pipeline/skills/shared/external/core-bluetooth/references/ble-patterns.md +257 -337
- package/pipeline/skills/shared/external/core-data/SKILL.md +292 -368
- package/pipeline/skills/shared/external/core-data/evals/evals.json +30 -27
- package/pipeline/skills/shared/external/core-motion/SKILL.md +235 -324
- package/pipeline/skills/shared/external/core-motion/evals/evals.json +31 -27
- package/pipeline/skills/shared/external/core-motion/references/motion-patterns.md +210 -310
- package/pipeline/skills/shared/external/core-nfc/SKILL.md +292 -366
- package/pipeline/skills/shared/external/core-nfc/evals/evals.json +22 -24
- package/pipeline/skills/shared/external/core-nfc/references/nfc-patterns.md +233 -329
- package/pipeline/skills/shared/external/coreml/SKILL.md +323 -367
- package/pipeline/skills/shared/external/coreml/evals/evals.json +24 -21
- package/pipeline/skills/shared/external/coreml/references/coreml-swift-integration.md +562 -565
- package/pipeline/skills/shared/external/cryptokit/SKILL.md +253 -394
- package/pipeline/skills/shared/external/cryptokit/evals/evals.json +20 -18
- package/pipeline/skills/shared/external/cryptokit/references/cryptokit-patterns.md +299 -488
- package/pipeline/skills/shared/external/debugging-instruments/SKILL.md +270 -323
- package/pipeline/skills/shared/external/debugging-instruments/evals/evals.json +27 -30
- package/pipeline/skills/shared/external/debugging-instruments/references/instruments-guide.md +167 -315
- package/pipeline/skills/shared/external/debugging-instruments/references/lldb-patterns.md +140 -193
- package/pipeline/skills/shared/external/device-integrity/SKILL.md +230 -353
- package/pipeline/skills/shared/external/device-integrity/evals/evals.json +25 -21
- package/pipeline/skills/shared/external/device-integrity/references/device-integrity-patterns.md +159 -197
- package/pipeline/skills/shared/external/energykit/SKILL.md +225 -392
- package/pipeline/skills/shared/external/energykit/evals/evals.json +29 -28
- package/pipeline/skills/shared/external/energykit/references/energykit-patterns.md +174 -470
- package/pipeline/skills/shared/external/eventkit-calendar/SKILL.md +261 -383
- package/pipeline/skills/shared/external/eventkit-calendar/evals/evals.json +25 -22
- package/pipeline/skills/shared/external/eventkit-calendar/references/eventkit-patterns.md +165 -268
- package/pipeline/skills/shared/external/healthkit/SKILL.md +252 -303
- package/pipeline/skills/shared/external/healthkit/evals/evals.json +24 -23
- package/pipeline/skills/shared/external/healthkit/references/healthkit-patterns.md +369 -523
- package/pipeline/skills/shared/external/homekit-matter/SKILL.md +233 -348
- package/pipeline/skills/shared/external/homekit-matter/evals/evals.json +27 -22
- package/pipeline/skills/shared/external/homekit-matter/references/matter-commissioning.md +199 -305
- package/pipeline/skills/shared/external/ios-accessibility/SKILL.md +368 -340
- package/pipeline/skills/shared/external/ios-accessibility/evals/evals.json +28 -27
- package/pipeline/skills/shared/external/ios-accessibility/references/a11y-patterns.md +314 -260
- package/pipeline/skills/shared/external/ios-accessibility/references/media-accessibility.md +97 -67
- package/pipeline/skills/shared/external/ios-accessibility/references/nutrition-labels.md +165 -101
- package/pipeline/skills/shared/external/ios-localization/SKILL.md +258 -371
- package/pipeline/skills/shared/external/ios-localization/evals/evals.json +23 -23
- package/pipeline/skills/shared/external/ios-localization/references/formatstyle-locale.md +283 -491
- package/pipeline/skills/shared/external/ios-localization/references/string-catalogs.md +313 -440
- package/pipeline/skills/shared/external/ios-networking/SKILL.md +265 -341
- package/pipeline/skills/shared/external/ios-networking/evals/evals.json +24 -24
- package/pipeline/skills/shared/external/ios-networking/references/background-websocket.md +425 -652
- package/pipeline/skills/shared/external/ios-networking/references/file-storage-patterns.md +143 -285
- package/pipeline/skills/shared/external/ios-networking/references/lightweight-clients.md +93 -53
- package/pipeline/skills/shared/external/ios-networking/references/network-framework.md +231 -456
- package/pipeline/skills/shared/external/ios-networking/references/urlsession-patterns.md +517 -784
- package/pipeline/skills/shared/external/ios-simulator/SKILL.md +265 -393
- package/pipeline/skills/shared/external/ios-simulator/evals/evals.json +21 -21
- package/pipeline/skills/shared/external/ios-simulator/references/simctl-commands.md +177 -270
- package/pipeline/skills/shared/external/live-activities/SKILL.md +318 -360
- package/pipeline/skills/shared/external/live-activities/evals/evals.json +21 -21
- package/pipeline/skills/shared/external/live-activities/references/activitykit-patterns.md +478 -710
- package/pipeline/skills/shared/external/mapkit-location/SKILL.md +295 -267
- package/pipeline/skills/shared/external/mapkit-location/evals/evals.json +28 -24
- package/pipeline/skills/shared/external/mapkit-location/references/mapkit-corelocation-patterns.md +378 -532
- package/pipeline/skills/shared/external/mapkit-location/references/mapkit-patterns.md +397 -499
- package/pipeline/skills/shared/external/metrickit-diagnostics/SKILL.md +165 -348
- package/pipeline/skills/shared/external/metrickit-diagnostics/evals/evals.json +26 -23
- package/pipeline/skills/shared/external/metrickit-diagnostics/references/metrickit-patterns.md +123 -130
- package/pipeline/skills/shared/external/musickit-audio/SKILL.md +189 -315
- package/pipeline/skills/shared/external/musickit-audio/evals/evals.json +22 -21
- package/pipeline/skills/shared/external/musickit-audio/references/musickit-patterns.md +181 -270
- package/pipeline/skills/shared/external/natural-language/SKILL.md +188 -340
- package/pipeline/skills/shared/external/natural-language/evals/evals.json +21 -21
- package/pipeline/skills/shared/external/natural-language/references/translation-patterns.md +171 -225
- package/pipeline/skills/shared/external/passkit-wallet/SKILL.md +258 -392
- package/pipeline/skills/shared/external/passkit-wallet/evals/evals.json +30 -29
- package/pipeline/skills/shared/external/passkit-wallet/references/wallet-passes.md +164 -231
- package/pipeline/skills/shared/external/pdfkit/SKILL.md +312 -344
- package/pipeline/skills/shared/external/pdfkit/evals/evals.json +19 -19
- package/pipeline/skills/shared/external/pdfkit/references/pdfkit-patterns.md +413 -624
- package/pipeline/skills/shared/external/pencilkit-drawing/SKILL.md +242 -358
- package/pipeline/skills/shared/external/pencilkit-drawing/evals/evals.json +25 -21
- package/pipeline/skills/shared/external/pencilkit-drawing/references/pencilkit-patterns.md +161 -226
- package/pipeline/skills/shared/external/permissionkit/SKILL.md +282 -400
- package/pipeline/skills/shared/external/permissionkit/evals/evals.json +27 -30
- package/pipeline/skills/shared/external/permissionkit/references/permissionkit-patterns.md +237 -350
- package/pipeline/skills/shared/external/photos-camera-media/SKILL.md +276 -325
- package/pipeline/skills/shared/external/photos-camera-media/references/av-playback.md +299 -545
- package/pipeline/skills/shared/external/photos-camera-media/references/camera-capture.md +344 -588
- package/pipeline/skills/shared/external/photos-camera-media/references/image-loading-caching.md +316 -660
- package/pipeline/skills/shared/external/photos-camera-media/references/photokit-patterns.md +270 -416
- package/pipeline/skills/shared/external/push-notifications/SKILL.md +312 -340
- package/pipeline/skills/shared/external/push-notifications/evals/evals.json +27 -26
- package/pipeline/skills/shared/external/push-notifications/references/notification-patterns.md +328 -485
- package/pipeline/skills/shared/external/push-notifications/references/rich-notifications.md +327 -560
- package/pipeline/skills/shared/external/realitykit-ar/SKILL.md +218 -410
- package/pipeline/skills/shared/external/realitykit-ar/evals/evals.json +24 -27
- package/pipeline/skills/shared/external/realitykit-ar/references/realitykit-patterns.md +221 -348
- package/pipeline/skills/shared/external/shareplay-activities/SKILL.md +222 -393
- package/pipeline/skills/shared/external/shareplay-activities/evals/evals.json +23 -24
- package/pipeline/skills/shared/external/shareplay-activities/references/shareplay-patterns.md +280 -420
- package/pipeline/skills/shared/external/speech-recognition/SKILL.md +217 -421
- package/pipeline/skills/shared/external/speech-recognition/evals/evals.json +23 -26
- package/pipeline/skills/shared/external/speech-recognition/references/speechanalyzer-patterns.md +133 -125
- package/pipeline/skills/shared/external/storekit/SKILL.md +228 -204
- package/pipeline/skills/shared/external/storekit/evals/evals.json +27 -24
- package/pipeline/skills/shared/external/storekit/references/app-review-guidelines.md +98 -109
- package/pipeline/skills/shared/external/storekit/references/core-patterns.md +298 -242
- package/pipeline/skills/shared/external/storekit/references/storekit-advanced.md +356 -649
- package/pipeline/skills/shared/external/swift-api-design-guidelines/SKILL.md +274 -399
- package/pipeline/skills/shared/external/swift-api-design-guidelines/evals/evals.json +22 -24
- package/pipeline/skills/shared/external/swift-api-design-guidelines/references/argument-labels-and-parameters.md +107 -108
- package/pipeline/skills/shared/external/swift-api-design-guidelines/references/conventions-and-special-rules.md +93 -165
- package/pipeline/skills/shared/external/swift-api-design-guidelines/references/naming-and-clarity.md +99 -137
- package/pipeline/skills/shared/external/swift-api-design-guidelines/references/side-effects-and-mutating-pairs.md +77 -120
- package/pipeline/skills/shared/external/swift-architecture/SKILL.md +334 -350
- package/pipeline/skills/shared/external/swift-architecture/evals/evals.json +22 -22
- package/pipeline/skills/shared/external/swift-charts/SKILL.md +208 -394
- package/pipeline/skills/shared/external/swift-charts/evals/evals.json +27 -30
- package/pipeline/skills/shared/external/swift-charts/references/charts-patterns.md +351 -762
- package/pipeline/skills/shared/external/swift-codable/SKILL.md +339 -343
- package/pipeline/skills/shared/external/swift-codable/evals/evals.json +20 -20
- package/pipeline/skills/shared/external/swift-concurrency/SKILL.md +303 -351
- package/pipeline/skills/shared/external/swift-concurrency/evals/evals.json +27 -24
- package/pipeline/skills/shared/external/swift-concurrency/references/approachable-concurrency.md +65 -80
- package/pipeline/skills/shared/external/swift-concurrency/references/async-algorithms.md +48 -84
- package/pipeline/skills/shared/external/swift-concurrency/references/bridging-interop.md +134 -79
- package/pipeline/skills/shared/external/swift-concurrency/references/concurrency-patterns.md +145 -167
- package/pipeline/skills/shared/external/swift-concurrency/references/diagnostics.md +62 -50
- package/pipeline/skills/shared/external/swift-concurrency/references/swiftui-concurrency.md +92 -121
- package/pipeline/skills/shared/external/swift-concurrency/references/synchronization-primitives.md +177 -241
- package/pipeline/skills/shared/external/swift-formatstyle/SKILL.md +258 -234
- package/pipeline/skills/shared/external/swift-language/SKILL.md +342 -382
- package/pipeline/skills/shared/external/swift-language/evals/evals.json +24 -27
- package/pipeline/skills/shared/external/swift-language/references/swift-attributes-interop.md +79 -56
- package/pipeline/skills/shared/external/swift-language/references/swift-patterns-extended.md +297 -340
- package/pipeline/skills/shared/external/swift-security/SKILL.md +180 -161
- package/pipeline/skills/shared/external/swift-security/evals/evals.json +25 -25
- package/pipeline/skills/shared/external/swift-security/references/biometric-authentication.md +314 -469
- package/pipeline/skills/shared/external/swift-security/references/certificate-trust.md +408 -476
- package/pipeline/skills/shared/external/swift-security/references/common-anti-patterns.md +260 -530
- package/pipeline/skills/shared/external/swift-security/references/compliance-owasp-mapping.md +270 -477
- package/pipeline/skills/shared/external/swift-security/references/credential-storage-patterns.md +573 -571
- package/pipeline/skills/shared/external/swift-security/references/cryptokit-public-key.md +370 -441
- package/pipeline/skills/shared/external/swift-security/references/cryptokit-symmetric.md +332 -433
- package/pipeline/skills/shared/external/swift-security/references/keychain-access-control.md +346 -468
- package/pipeline/skills/shared/external/swift-security/references/keychain-fundamentals.md +352 -472
- package/pipeline/skills/shared/external/swift-security/references/keychain-item-classes.md +431 -432
- package/pipeline/skills/shared/external/swift-security/references/keychain-sharing.md +328 -425
- package/pipeline/skills/shared/external/swift-security/references/migration-legacy-stores.md +341 -579
- package/pipeline/skills/shared/external/swift-security/references/secure-enclave.md +396 -457
- package/pipeline/skills/shared/external/swift-security/references/testing-security-code.md +354 -614
- package/pipeline/skills/shared/external/swift-testing/SKILL.md +188 -175
- package/pipeline/skills/shared/external/swift-testing/evals/evals.json +26 -24
- package/pipeline/skills/shared/external/swift-testing/references/testing-advanced.md +80 -84
- package/pipeline/skills/shared/external/swift-testing/references/testing-patterns.md +317 -433
- package/pipeline/skills/shared/external/swiftdata/SKILL.md +392 -256
- package/pipeline/skills/shared/external/swiftdata/evals/evals.json +24 -24
- package/pipeline/skills/shared/external/swiftdata/references/core-data-coexistence.md +206 -402
- package/pipeline/skills/shared/external/swiftdata/references/indexing.md +59 -52
- package/pipeline/skills/shared/external/swiftdata/references/predicate-pitfalls.md +57 -33
- package/pipeline/skills/shared/external/swiftdata/references/swiftdata-advanced.md +354 -747
- package/pipeline/skills/shared/external/swiftdata/references/swiftdata-queries.md +300 -508
- package/pipeline/skills/shared/external/swiftlint/SKILL.md +175 -226
- package/pipeline/skills/shared/external/swiftlint/references/adoption-and-configuration.md +141 -208
- package/pipeline/skills/shared/external/swiftlint/references/custom-rules-and-analyze.md +100 -109
- package/pipeline/skills/shared/external/swiftlint/references/plugins-run-scripts-and-integrations.md +159 -179
- package/pipeline/skills/shared/external/swiftlint/references/rule-reference.md +383 -18
- package/pipeline/skills/shared/external/swiftlint/references/rules-suppressions-and-baselines.md +143 -229
- package/pipeline/skills/shared/external/swiftui-animation/SKILL.md +283 -366
- package/pipeline/skills/shared/external/swiftui-animation/references/animation-advanced.md +396 -608
- package/pipeline/skills/shared/external/swiftui-animation/references/core-animation-bridge.md +336 -385
- package/pipeline/skills/shared/external/swiftui-gestures/SKILL.md +239 -349
- package/pipeline/skills/shared/external/swiftui-gestures/references/gesture-patterns.md +228 -310
- package/pipeline/skills/shared/external/swiftui-layout-components/SKILL.md +260 -249
- package/pipeline/skills/shared/external/swiftui-layout-components/references/form.md +92 -74
- package/pipeline/skills/shared/external/swiftui-layout-components/references/grids.md +112 -177
- package/pipeline/skills/shared/external/swiftui-layout-components/references/list.md +61 -64
- package/pipeline/skills/shared/external/swiftui-layout-components/references/scrollview.md +94 -134
- package/pipeline/skills/shared/external/swiftui-liquid-glass/SKILL.md +193 -225
- package/pipeline/skills/shared/external/swiftui-liquid-glass/references/liquid-glass.md +173 -327
- package/pipeline/skills/shared/external/swiftui-navigation/SKILL.md +193 -168
- package/pipeline/skills/shared/external/swiftui-navigation/references/deeplinks.md +127 -150
- package/pipeline/skills/shared/external/swiftui-navigation/references/navigationstack.md +132 -133
- package/pipeline/skills/shared/external/swiftui-navigation/references/sheets.md +152 -117
- package/pipeline/skills/shared/external/swiftui-navigation/references/tabview.md +106 -140
- package/pipeline/skills/shared/external/swiftui-patterns/SKILL.md +316 -252
- package/pipeline/skills/shared/external/swiftui-patterns/references/architecture-patterns.md +341 -332
- package/pipeline/skills/shared/external/swiftui-patterns/references/deprecated-migration.md +547 -854
- package/pipeline/skills/shared/external/swiftui-patterns/references/design-polish.md +485 -537
- package/pipeline/skills/shared/external/swiftui-patterns/references/platform-and-sharing.md +417 -499
- package/pipeline/skills/shared/external/swiftui-performance/SKILL.md +213 -376
- package/pipeline/skills/shared/external/swiftui-performance/references/demystify-swiftui-performance-wwdc23.md +86 -175
- package/pipeline/skills/shared/external/swiftui-performance/references/optimizing-swiftui-performance-instruments.md +89 -195
- package/pipeline/skills/shared/external/swiftui-performance/references/understanding-hangs-in-your-app.md +95 -182
- package/pipeline/skills/shared/external/swiftui-performance/references/understanding-improving-swiftui-performance.md +71 -149
- package/pipeline/skills/shared/external/swiftui-performance/references/wwdc-session-sources.md +21 -27
- package/pipeline/skills/shared/external/swiftui-uikit-interop/SKILL.md +303 -295
- package/pipeline/skills/shared/external/swiftui-uikit-interop/references/hosting-migration.md +204 -387
- package/pipeline/skills/shared/external/swiftui-uikit-interop/references/representable-recipes.md +469 -683
- package/pipeline/skills/shared/external/swiftui-webkit/SKILL.md +140 -186
- package/pipeline/skills/shared/external/swiftui-webkit/references/loading-and-observation.md +75 -86
- package/pipeline/skills/shared/external/swiftui-webkit/references/local-content-and-custom-schemes.md +63 -60
- package/pipeline/skills/shared/external/swiftui-webkit/references/migration-and-fallbacks.md +69 -137
- package/pipeline/skills/shared/external/swiftui-webkit/references/navigation-and-javascript.md +95 -67
- package/pipeline/skills/shared/external/tipkit/SKILL.md +220 -335
- package/pipeline/skills/shared/external/tipkit/references/tipkit-patterns.md +356 -494
- package/pipeline/skills/shared/external/vision-framework/SKILL.md +260 -375
- package/pipeline/skills/shared/external/vision-framework/references/vision-requests.md +393 -515
- package/pipeline/skills/shared/external/vision-framework/references/visionkit-scanner.md +363 -539
- package/pipeline/skills/shared/external/weatherkit/SKILL.md +152 -310
- package/pipeline/skills/shared/external/weatherkit/references/weatherkit-patterns.md +288 -407
- package/pipeline/skills/shared/external/widgetkit/SKILL.md +216 -288
- package/pipeline/skills/shared/external/widgetkit/references/widgetkit-advanced.md +414 -719
- package/pipeline/skills/shared/external/NOTICE-swift-ios-skills.md +0 -39
|
@@ -1,354 +1,212 @@
|
|
|
1
1
|
# File Storage Patterns
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
## Contents
|
|
7
|
-
|
|
8
|
-
- [Directory Selection Guide](#directory-selection-guide)
|
|
9
|
-
- [FileProtectionType Levels](#fileprotectiontype-levels)
|
|
10
|
-
- [Backup Exclusion (isExcludedFromBackup)](#backup-exclusion-isexcludedfrombackup)
|
|
11
|
-
- [Storage Pressure Handling](#storage-pressure-handling)
|
|
3
|
+
Downloaded and uploaded data has to live somewhere. Where it lives decides
|
|
4
|
+
whether it is backed up, whether the system may delete it, and when it can be
|
|
5
|
+
read.
|
|
12
6
|
|
|
13
7
|
## Directory Selection Guide
|
|
14
8
|
|
|
15
|
-
|
|
16
|
-
|
|
9
|
+
Ask three questions: did the user create it, can the app recreate it, and is
|
|
10
|
+
it only needed for the next few minutes?
|
|
17
11
|
|
|
18
|
-
| Directory | Backed
|
|
12
|
+
| Directory | Backed up | System may purge | Put here |
|
|
19
13
|
|---|---|---|---|
|
|
20
|
-
| `Documents/` | Yes | No |
|
|
21
|
-
| `Library/Application Support/` | Yes | No |
|
|
22
|
-
| `Library/Caches/` | No | Yes
|
|
23
|
-
| `tmp/` | No | Yes
|
|
14
|
+
| `Documents/` | Yes | No | Things the user made or explicitly saved |
|
|
15
|
+
| `Library/Application Support/` | Yes | No | Data the app itself owns: databases, configuration, caches that must survive an update |
|
|
16
|
+
| `Library/Caches/` | No | Yes, when storage runs low | Anything that can be downloaded or rebuilt |
|
|
17
|
+
| `tmp/` | No | Yes, at any time | Scratch files, in-flight upload bodies |
|
|
24
18
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
Use `FileManager.default.urls(for:in:)` to get the correct path. Never
|
|
28
|
-
hardcode paths.
|
|
19
|
+
Ask `FileManager` for the location; never build these paths by hand.
|
|
29
20
|
|
|
30
21
|
```swift
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
let
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
let
|
|
40
|
-
|
|
41
|
-
).first!
|
|
42
|
-
// Create if it doesn't exist (not auto-created)
|
|
43
|
-
try FileManager.default.createDirectory(
|
|
44
|
-
at: appSupportURL, withIntermediateDirectories: true
|
|
45
|
-
)
|
|
46
|
-
|
|
47
|
-
// Library/Caches/ - re-creatable data, not backed up, may be purged
|
|
48
|
-
let cachesURL = FileManager.default.urls(
|
|
49
|
-
for: .cachesDirectory, in: .userDomainMask
|
|
50
|
-
).first!
|
|
51
|
-
|
|
52
|
-
// tmp/ - temporary files, purged by system periodically
|
|
53
|
-
let tmpURL = FileManager.default.temporaryDirectory
|
|
22
|
+
let fm = FileManager.default
|
|
23
|
+
let documents = try fm.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: false)
|
|
24
|
+
let support = try fm.url(for: .applicationSupportDirectory, in: .userDomainMask, appropriateFor: nil, create: true)
|
|
25
|
+
let caches = try fm.url(for: .cachesDirectory, in: .userDomainMask, appropriateFor: nil, create: false)
|
|
26
|
+
let scratch = fm.temporaryDirectory
|
|
27
|
+
|
|
28
|
+
let exportedInvoice = documents.appending(path: "invoice-2031.pdf")
|
|
29
|
+
let catalogDatabase = support.appending(path: "catalog.sqlite")
|
|
30
|
+
let coverThumbnail = caches.appending(path: "covers/1182.jpg")
|
|
31
|
+
let pendingUpload = scratch.appending(path: "upload-\(UUID().uuidString).bin")
|
|
54
32
|
```
|
|
55
33
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
let exportURL = documentsURL.appendingPathComponent("Report.pdf")
|
|
61
|
-
try pdfData.write(to: exportURL)
|
|
62
|
-
|
|
63
|
-
// App's SQLite database - Library/Application Support/
|
|
64
|
-
let dbURL = appSupportURL.appendingPathComponent("AppData.sqlite")
|
|
65
|
-
|
|
66
|
-
// Downloaded thumbnail cache - Library/Caches/
|
|
67
|
-
let thumbURL = cachesURL.appendingPathComponent("thumbnails/\(imageID).jpg")
|
|
68
|
-
|
|
69
|
-
// In-progress upload - tmp/
|
|
70
|
-
let uploadURL = tmpURL.appendingPathComponent(UUID().uuidString + ".tmp")
|
|
71
|
-
```
|
|
34
|
+
`FileManager.default.urls(for:in:)` returns the same locations as an array.
|
|
35
|
+
Application Support does not exist on a fresh install. Pass `create: true`
|
|
36
|
+
as above, or call `createDirectory(at:withIntermediateDirectories: true)`
|
|
37
|
+
before writing into it.
|
|
72
38
|
|
|
73
39
|
## FileProtectionType Levels
|
|
74
40
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
[Encrypting Your App's Files](https://sosumi.ai/documentation/uikit/encrypting-your-app-s-files)
|
|
41
|
+
Data Protection encrypts files at rest, and the protection level decides
|
|
42
|
+
whether a file can be read while the device is locked. See the
|
|
43
|
+
[protection type reference](https://developer.apple.com/documentation/foundation/fileprotectiontype)
|
|
44
|
+
and the [file encryption article](https://developer.apple.com/documentation/uikit/encrypting-your-app-s-files).
|
|
80
45
|
|
|
81
|
-
| Level |
|
|
82
|
-
|
|
83
|
-
|
|
|
84
|
-
|
|
|
85
|
-
|
|
|
86
|
-
|
|
|
87
|
-
|
|
88
|
-
### Setting File Protection
|
|
46
|
+
| Level | Readable | Good for |
|
|
47
|
+
|---|---|---|
|
|
48
|
+
| `.complete` | Only while unlocked | Health, finance and other sensitive records |
|
|
49
|
+
| `.completeUnlessOpen` | A file opened before locking stays usable | Recordings or downloads in progress at lock time |
|
|
50
|
+
| `.completeUntilFirstUserAuthentication` | Any time after the first unlock since boot (the default) | Most app data, including data used in the background |
|
|
51
|
+
| `.none` | Always, even before the first unlock | Non-sensitive data needed at boot |
|
|
89
52
|
|
|
90
53
|
```swift
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
// Option 1: Set protection when writing data
|
|
94
|
-
try sensitiveData.write(to: fileURL, options: .completeFileProtection)
|
|
95
|
-
|
|
96
|
-
// Option 2: Set protection via FileManager attributes
|
|
97
|
-
try FileManager.default.setAttributes(
|
|
98
|
-
[.protectionKey: FileProtectionType.complete],
|
|
99
|
-
ofItemAtPath: fileURL.path
|
|
100
|
-
)
|
|
101
|
-
|
|
102
|
-
// Option 3: Set protection on a directory (applies to new files within)
|
|
103
|
-
try FileManager.default.setAttributes(
|
|
104
|
-
[.protectionKey: FileProtectionType.complete],
|
|
105
|
-
ofItemAtPath: secureDirectoryURL.path
|
|
106
|
-
)
|
|
107
|
-
```
|
|
54
|
+
try statement.write(to: fileURL, options: .completeFileProtection)
|
|
108
55
|
|
|
109
|
-
|
|
56
|
+
let files = FileManager.default
|
|
57
|
+
let lockedDown: [FileAttributeKey: Any] = [.protectionKey: FileProtectionType.complete]
|
|
58
|
+
try files.setAttributes(lockedDown, ofItemAtPath: vaultFolder.path())
|
|
110
59
|
|
|
111
|
-
|
|
112
|
-
let
|
|
113
|
-
if let protection = attributes[.protectionKey] as? FileProtectionType {
|
|
114
|
-
switch protection {
|
|
115
|
-
case .complete:
|
|
116
|
-
print("File is fully protected")
|
|
117
|
-
case .completeUnlessOpen:
|
|
118
|
-
print("Protected unless already open")
|
|
119
|
-
case .completeUntilFirstUserAuthentication:
|
|
120
|
-
print("Protected until first unlock (default)")
|
|
121
|
-
case .none:
|
|
122
|
-
print("No encryption")
|
|
123
|
-
default:
|
|
124
|
-
break
|
|
125
|
-
}
|
|
126
|
-
}
|
|
60
|
+
let attributes = try files.attributesOfItem(atPath: fileURL.path())
|
|
61
|
+
let level = attributes[.protectionKey] as? FileProtectionType
|
|
127
62
|
```
|
|
128
63
|
|
|
129
|
-
|
|
64
|
+
Protection set on a directory applies to files created in it afterwards.
|
|
130
65
|
|
|
131
|
-
|
|
132
|
-
|
|
66
|
+
A `.complete` file cannot be opened while the device is locked. Check
|
|
67
|
+
`UIApplication.shared.isProtectedDataAvailable` before touching one, and
|
|
68
|
+
watch the transitions:
|
|
133
69
|
|
|
134
70
|
```swift
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
if UIApplication.shared.isProtectedDataAvailable {
|
|
139
|
-
// Safe to read .complete files
|
|
140
|
-
let data = try Data(contentsOf: protectedFileURL)
|
|
141
|
-
} else {
|
|
142
|
-
// Wait for device unlock
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
// Observe availability changes
|
|
146
|
-
NotificationCenter.default.addObserver(
|
|
147
|
-
forName: UIApplication.protectedDataDidBecomeAvailableNotification,
|
|
148
|
-
object: nil,
|
|
149
|
-
queue: .main
|
|
150
|
-
) { _ in
|
|
151
|
-
// Protected files are now accessible
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
NotificationCenter.default.addObserver(
|
|
155
|
-
forName: UIApplication.protectedDataWillBecomeUnavailableNotification,
|
|
156
|
-
object: nil,
|
|
157
|
-
queue: .main
|
|
158
|
-
) { _ in
|
|
159
|
-
// Close file handles to .complete files
|
|
160
|
-
}
|
|
71
|
+
let center = NotificationCenter.default
|
|
72
|
+
let lockSoon = center.notifications(named: UIApplication.protectedDataWillBecomeUnavailableNotification)
|
|
73
|
+
let unlocked = center.notifications(named: UIApplication.protectedDataDidBecomeAvailableNotification)
|
|
161
74
|
```
|
|
162
75
|
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
Exclude large re-downloadable content from iCloud/iTunes backup to avoid
|
|
166
|
-
bloating the user's backup. Apple may reject apps that back up excessive
|
|
167
|
-
re-creatable data.
|
|
76
|
+
Close handles to `.complete` files when the will-become-unavailable
|
|
77
|
+
notification arrives; reopen them after the did-become-available one.
|
|
168
78
|
|
|
169
|
-
|
|
79
|
+
## Backup Exclusion (isExcludedFromBackup)
|
|
170
80
|
|
|
171
|
-
|
|
81
|
+
Large content that can be fetched again should not go into iCloud or
|
|
82
|
+
computer backups. App Review can reject an app that backs up a lot of
|
|
83
|
+
re-creatable data. See the
|
|
84
|
+
[resource values reference](https://developer.apple.com/documentation/foundation/urlresourcevalues).
|
|
172
85
|
|
|
173
86
|
```swift
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
resourceValues.isExcludedFromBackup = true
|
|
180
|
-
var mutableURL = url
|
|
181
|
-
try mutableURL.setResourceValues(resourceValues)
|
|
87
|
+
func keepOutOfBackup(_ item: URL) throws {
|
|
88
|
+
var target = item
|
|
89
|
+
var values = URLResourceValues()
|
|
90
|
+
values.isExcludedFromBackup = true
|
|
91
|
+
try target.setResourceValues(values)
|
|
182
92
|
}
|
|
183
93
|
|
|
184
|
-
|
|
185
|
-
let
|
|
186
|
-
try excludeFromBackup(largeCache)
|
|
187
|
-
```
|
|
188
|
-
|
|
189
|
-
### Checking the Exclusion Flag
|
|
190
|
-
|
|
191
|
-
```swift
|
|
192
|
-
func isExcludedFromBackup(_ url: URL) throws -> Bool {
|
|
193
|
-
let values = try url.resourceValues(forKeys: [.isExcludedFromBackupKey])
|
|
94
|
+
func skipsBackup(_ item: URL) throws -> Bool {
|
|
95
|
+
let values = try item.resourceValues(forKeys: [.isExcludedFromBackupKey])
|
|
194
96
|
return values.isExcludedFromBackup ?? false
|
|
195
97
|
}
|
|
196
98
|
```
|
|
197
99
|
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
| Exclude | Keep in Backup |
|
|
100
|
+
| Exclude | Keep in backup |
|
|
201
101
|
|---|---|
|
|
202
|
-
| Downloaded media
|
|
203
|
-
| API response caches |
|
|
204
|
-
| Generated thumbnails
|
|
205
|
-
|
|
|
206
|
-
|
|
|
102
|
+
| Downloaded media | The user's documents |
|
|
103
|
+
| API response caches | Preferences and settings |
|
|
104
|
+
| Generated thumbnails and previews | Databases holding user data |
|
|
105
|
+
| Map tiles cached for offline use | In-app purchase receipts |
|
|
106
|
+
| Precomputed search indexes | Anything the user created |
|
|
207
107
|
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
```swift
|
|
213
|
-
let offlineDataURL = appSupportURL.appendingPathComponent("OfflineData")
|
|
214
|
-
try FileManager.default.createDirectory(
|
|
215
|
-
at: offlineDataURL, withIntermediateDirectories: true
|
|
216
|
-
)
|
|
217
|
-
try excludeFromBackup(offlineDataURL)
|
|
218
|
-
|
|
219
|
-
// Files in this directory persist across app updates but don't bloat backup
|
|
220
|
-
try downloadedData.write(to: offlineDataURL.appendingPathComponent("map-tiles.db"))
|
|
221
|
-
```
|
|
108
|
+
A useful middle ground: put re-downloadable data in a subfolder of
|
|
109
|
+
Application Support and exclude that folder from backup. It survives app
|
|
110
|
+
updates and system purges without inflating the backup.
|
|
222
111
|
|
|
223
112
|
## Storage Pressure Handling
|
|
224
113
|
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
114
|
+
Once free space gets tight, iOS may empty `Library/Caches/` and
|
|
115
|
+
`tmp/` without asking. Do not rely on that alone; keep your own footprint in
|
|
116
|
+
check.
|
|
228
117
|
|
|
229
|
-
###
|
|
118
|
+
### Measuring free space
|
|
230
119
|
|
|
231
120
|
```swift
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
let values = try URL(
|
|
236
|
-
|
|
237
|
-
|
|
121
|
+
func freeBytes(forImportantWork important: Bool) throws -> Int64 {
|
|
122
|
+
let key: URLResourceKey = important ? .volumeAvailableCapacityForImportantUsageKey
|
|
123
|
+
: .volumeAvailableCapacityForOpportunisticUsageKey
|
|
124
|
+
let values = try URL.homeDirectory.resourceValues(forKeys: [key])
|
|
125
|
+
return (important ? values.volumeAvailableCapacityForImportantUsage
|
|
126
|
+
: values.volumeAvailableCapacityForOpportunisticUsage) ?? 0
|
|
238
127
|
}
|
|
239
128
|
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
// The opportunistic value is always <= the important value
|
|
243
|
-
|
|
244
|
-
func hasSpaceForDownload(bytes: Int64) throws -> Bool {
|
|
245
|
-
let available = try availableDiskSpace()
|
|
246
|
-
return available > bytes
|
|
129
|
+
func hasRoom(for byteCount: Int64) -> Bool {
|
|
130
|
+
((try? freeBytes(forImportantWork: true)) ?? 0) >= byteCount
|
|
247
131
|
}
|
|
248
132
|
```
|
|
249
133
|
|
|
250
|
-
|
|
134
|
+
Use the important-usage figure for work the user asked for and the
|
|
135
|
+
opportunistic figure for optional work such as prefetching. The
|
|
136
|
+
opportunistic value is never larger than the important one.
|
|
251
137
|
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
NotificationCenter.default.addObserver(
|
|
257
|
-
forName: UIApplication.didReceiveMemoryWarningNotification,
|
|
258
|
-
object: nil,
|
|
259
|
-
queue: .main
|
|
260
|
-
) { _ in
|
|
261
|
-
// Clear in-memory caches; consider trimming disk caches too
|
|
262
|
-
clearImageCache()
|
|
263
|
-
}
|
|
138
|
+
### Where low-disk signals actually come from
|
|
139
|
+
|
|
140
|
+
There is no general system notification that says storage is low. The
|
|
141
|
+
signals an app can use are:
|
|
264
142
|
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
143
|
+
- The capacity keys above, read at launch and before any large download,
|
|
144
|
+
export or cache fill. Below a threshold you choose (for example 100 MB),
|
|
145
|
+
run cleanup and skip optional work.
|
|
146
|
+
- Write failures. A write that runs out of space throws
|
|
147
|
+
`CocoaError(.fileWriteOutOfSpace)` (POSIX `ENOSPC` underneath). Catch it,
|
|
148
|
+
free cache space, and retry once or tell the user.
|
|
149
|
+
- `NSBundleResourceRequestLowDiskSpace`, posted only to apps that use
|
|
150
|
+
On-Demand Resources, when the system needs space back from them.
|
|
269
151
|
|
|
270
|
-
|
|
271
|
-
|
|
152
|
+
`UIApplication.didReceiveMemoryWarningNotification` is about RAM, not disk.
|
|
153
|
+
Respond to it by dropping in-memory caches (an `NSCache` does this on its
|
|
154
|
+
own); it says nothing about free storage and is not a reason to delete files.
|
|
155
|
+
|
|
156
|
+
```swift
|
|
157
|
+
func writeCache(_ blob: Data, into file: URL, cleaner: CacheJanitor) throws {
|
|
158
|
+
do {
|
|
159
|
+
try blob.write(to: file, options: .atomic)
|
|
160
|
+
} catch let failure as CocoaError where failure.code == .fileWriteOutOfSpace {
|
|
161
|
+
try cleaner.sweep()
|
|
162
|
+
try blob.write(to: file, options: .atomic)
|
|
272
163
|
}
|
|
273
164
|
}
|
|
274
165
|
```
|
|
275
166
|
|
|
276
|
-
###
|
|
167
|
+
### Cleaning a cache directory
|
|
277
168
|
|
|
278
169
|
```swift
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
let maxCacheAge: TimeInterval // e.g., 7 days
|
|
284
|
-
let maxCacheSize: Int64 // e.g., 500 MB
|
|
285
|
-
|
|
286
|
-
/// Remove files older than maxCacheAge
|
|
287
|
-
func removeExpiredFiles() throws {
|
|
288
|
-
let contents = try FileManager.default.contentsOfDirectory(
|
|
289
|
-
at: cachesURL,
|
|
290
|
-
includingPropertiesForKeys: [.contentModificationDateKey, .fileSizeKey],
|
|
291
|
-
options: .skipsHiddenFiles
|
|
292
|
-
)
|
|
293
|
-
|
|
294
|
-
let cutoff = Date.now.addingTimeInterval(-maxCacheAge)
|
|
295
|
-
|
|
296
|
-
for fileURL in contents {
|
|
297
|
-
let values = try fileURL.resourceValues(
|
|
298
|
-
forKeys: [.contentModificationDateKey]
|
|
299
|
-
)
|
|
300
|
-
if let modified = values.contentModificationDate, modified < cutoff {
|
|
301
|
-
try FileManager.default.removeItem(at: fileURL)
|
|
302
|
-
}
|
|
303
|
-
}
|
|
304
|
-
}
|
|
170
|
+
struct CacheJanitor {
|
|
171
|
+
let folder: URL
|
|
172
|
+
var maxAge: Duration = .seconds(7 * 24 * 60 * 60)
|
|
173
|
+
var maxBytes = 500 * 1024 * 1024
|
|
305
174
|
|
|
306
|
-
|
|
307
|
-
func trimToSize() throws {
|
|
308
|
-
let contents = try FileManager.default.contentsOfDirectory(
|
|
309
|
-
at: cachesURL,
|
|
310
|
-
includingPropertiesForKeys: [.contentModificationDateKey, .fileSizeKey],
|
|
311
|
-
options: .skipsHiddenFiles
|
|
312
|
-
)
|
|
313
|
-
|
|
314
|
-
// Sort oldest first
|
|
315
|
-
let sorted = try contents.sorted { a, b in
|
|
316
|
-
let aDate = try a.resourceValues(forKeys: [.contentModificationDateKey])
|
|
317
|
-
.contentModificationDate ?? .distantPast
|
|
318
|
-
let bDate = try b.resourceValues(forKeys: [.contentModificationDateKey])
|
|
319
|
-
.contentModificationDate ?? .distantPast
|
|
320
|
-
return aDate < bDate
|
|
321
|
-
}
|
|
175
|
+
private struct Entry { let url: URL; let modified: Date; let size: Int }
|
|
322
176
|
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
177
|
+
func sweep() throws {
|
|
178
|
+
try removeExpired()
|
|
179
|
+
try trimToBudget()
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
func removeExpired() throws {
|
|
183
|
+
let cutoff = Date.now.addingTimeInterval(-Double(maxAge.components.seconds))
|
|
184
|
+
for entry in try entries() where entry.modified < cutoff {
|
|
185
|
+
try FileManager.default.removeItem(at: entry.url)
|
|
328
186
|
}
|
|
187
|
+
}
|
|
329
188
|
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
totalSize -= fileSize
|
|
189
|
+
func trimToBudget() throws {
|
|
190
|
+
let oldestFirst = try entries().sorted { $0.modified < $1.modified }
|
|
191
|
+
var total = oldestFirst.reduce(0) { $0 + $1.size }
|
|
192
|
+
for entry in oldestFirst where total > maxBytes {
|
|
193
|
+
try FileManager.default.removeItem(at: entry.url)
|
|
194
|
+
total -= entry.size
|
|
337
195
|
}
|
|
338
196
|
}
|
|
339
197
|
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
try
|
|
343
|
-
|
|
198
|
+
private func entries() throws -> [Entry] {
|
|
199
|
+
let keys: [URLResourceKey] = [.contentModificationDateKey, .fileSizeKey]
|
|
200
|
+
return try FileManager.default
|
|
201
|
+
.contentsOfDirectory(at: folder, includingPropertiesForKeys: keys, options: .skipsHiddenFiles)
|
|
202
|
+
.compactMap { item in
|
|
203
|
+
let info = try item.resourceValues(forKeys: Set(keys))
|
|
204
|
+
guard let modified = info.contentModificationDate else { return nil }
|
|
205
|
+
return Entry(url: item, modified: modified, size: info.fileSize ?? 0)
|
|
206
|
+
}
|
|
344
207
|
}
|
|
345
208
|
}
|
|
346
|
-
|
|
347
|
-
// Usage
|
|
348
|
-
let cleaner = StorageCleaner(
|
|
349
|
-
cachesURL: FileManager.default.urls(for: .cachesDirectory, in: .userDomainMask).first!,
|
|
350
|
-
maxCacheAge: 7 * 24 * 60 * 60, // 7 days
|
|
351
|
-
maxCacheSize: 500 * 1024 * 1024 // 500 MB
|
|
352
|
-
)
|
|
353
|
-
try cleaner.performCleanup()
|
|
354
209
|
```
|
|
210
|
+
|
|
211
|
+
`sweep()` deletes files past their age first, then removes the least
|
|
212
|
+
recently modified files until the folder fits its size budget.
|