Repository navigation
Releases: crimsondhakx/xcprune
Release list
v1.0.1
Fixes a false positive that affected any project localizing UI through XIBs or storyboards.
The bug
Xcode extracts a XIB's localizable strings into keys shaped <objectID>.<keyPath>, such as 0cO-dq-wRh.headerCell.title. The nib loader applies them by matching the object ID at load time, so the key is never written in source and has no generated symbol. Both matching strategies missed it, and live UI strings were reported as unused.
Measured against NetNewsWire:
| v1.0.0 | v1.0.1 | |
|---|---|---|
| Unused localization keys reported | 39 | 4 |
| of which were live XIB strings | 35 | 0 |
If you ran v1.0.0 on a project with localized XIBs, treat its localization-key results as unreliable and re-run. Asset results were not affected.
The fix
Interface files now contribute their id="..." values, and a localization key counts as referenced when its leading dot-component matches a known object ID. Scoped narrowly: assets are not excused by a XIB object sharing a name, an ordinary dotted key like settings.title is still reported, and a key whose object ID appears nowhere is still reported.
Full detail in #4.
v1.0.0
Find unused images, colors, and localization keys in an Xcode project.
Every app accumulates dead resources — an image that outlived the screen using it, a localization key that outlived its copy — and Xcode never tells you. They ship in every download indefinitely.
Why another one
The existing tools for this were abandoned years ago, and none understand a modern project. Since Xcode 15 the compiler generates a Swift symbol per asset, so idiomatic code reads Image(.profileAvatar) and the asset name may never appear as a string literal at all. A tool that only greps for strings reports nearly the whole catalogue as unused, which is worse than no tool.
What counts as a use
- the name as a string literal, Swift or Objective-C
- the symbol Xcode generates, so
Image(.profileAvatar)reachesprofile_avatar - storyboard and xib attributes, so
image="header"counts Info.plistentries, so app icons and launch images count- implicit SwiftUI localization, so
Text("welcome")reaches the keywelcome
Reads asset catalogs including namespaced folders, and keys from .strings, .stringsdict, and the .xcstrings string catalog.
It never deletes
No static tool can be certain. UIImage(named: iconName) resolves at runtime, so any asset could be the one it loads. Where such a lookup exists xcprune names the file and line and marks that kind low confidence, rather than staying quiet and letting you delete shipping content.
A missed dead asset costs bytes. A false positive costs a blank screen in production. The bias is deliberate.
Use
xcprune # scan the current directory
xcprune --only localizationKey
xcprune --format json
xcprune --format github --fail-on-unused # for CIComplements periphery, which finds unused Swift code. No overlap.
Requires macOS 12 or newer. No external dependencies.