回答:
プロジェクトに含まれていないが、フォルダにたどり着くだけのファイルの場合は、
cmd ⌘+ alt ⌥+A
そして、それらは淡色表示されません。
xibでもコードでも参照されていないファイルの場合、次のようなものが機能する可能性があります。
#!/bin/sh
PROJ=`find . -name '*.xib' -o -name '*.[mh]'`
find . -iname '*.png' | while read png
do
name=`basename $png`
if ! grep -qhs "$name" "$PROJ"; then
echo "$png is not referenced"
fi
done
これは、より堅牢なソリューションである-それはのためにチェックする任意の任意のテキストファイル内のベース名を参照します。ストーリーボードファイルを含まない上記のソリューションに注意してください(完全に理解可能で、当時は存在しませんでした)。
Ackはこれをかなり高速にしますが、このスクリプトが頻繁に実行される場合は、いくつかの明らかな最適化を行う必要があります。たとえば、retinaとnon-retinaの両方のアセットがある場合、このコードはすべてのベース名を2回チェックします。
#!/bin/bash
for i in `find . -name "*.png" -o -name "*.jpg"`; do
file=`basename -s .jpg "$i" | xargs basename -s .png | xargs basename -s @2x`
result=`ack -i "$file"`
if [ -z "$result" ]; then
echo "$i"
fi
done
# Ex: to remove from git
# for i in `./script/unused_images.sh`; do git rm "$i"; done
chmod a+x FindUnusedImages.sh
)にして、bashの他のプログラムと同じように実行する必要があります./FindUnusedImages.sh
result=`ack --ignore-file=match:/.\.pbxproj/ -i "$file"`
これにはack 2.0以降が必要です
LSUnusedResourcesを試してみてください。
jeffhodnettのUnusedの影響を強く受けていますが、正直に言って、Unusedは非常に遅く、結果は完全に正しくありません。そこで、パフォーマンスの最適化を行いました。検索速度は未使用よりも高速です。
Romanの解決策を試し、網膜の画像を処理するためにいくつかの調整を加えました。これはうまく機能しますが、イメージ名はプログラムでコードで生成でき、このスクリプトはこれらのイメージを参照されていないものとして誤ってリストすることに注意してください。たとえば、
NSString *imageName = [NSString stringWithFormat:@"image_%d.png", 1];
このスクリプトimage_1.png
は、参照されていないと誤って見なします。
変更されたスクリプトは次のとおりです。
#!/bin/sh
PROJ=`find . -name '*.xib' -o -name '*.[mh]' -o -name '*.storyboard' -o -name '*.mm'`
for png in `find . -name '*.png'`
do
name=`basename -s .png $png`
name=`basename -s @2x $name`
if ! grep -qhs "$name" "$PROJ"; then
echo "$png"
fi
done
ファイル名のスペースも処理するこのスクリプトだけが私のために機能しています:
swift
ファイルとをサポートするように更新されましたcocoapod
。デフォルトでは、ポッドディレクトリは除外され、プロジェクトファイルのみがチェックされます。実行して--pod
Pods フォルダーもチェックするには、attrbiute を指定して実行します。
/.finunusedimages.sh --pod
実際のスクリプトは次のとおりです。
#!/bin/sh
#varables
baseCmd="find ."
attrs="-name '*.xib' -o -name '*.[mh]' -o -name '*.storyboard' -o -name '*.mm' -o -name '*.swift'"
excudePodFiles="-not \( -path */Pods/* -prune \)"
imgPathes="find . -iname '*.png' -print0"
#finalize commands
if [ "$1" != "--pod" ]; then
echo "Pod files excluded"
attrs="$excudePodFiles $attrs"
imgPathes="find . $excudePodFiles -iname '*.png' -print0"
fi
#select project files to check
projFiles=`eval "$baseCmd $attrs"`
echo "Looking for in files: $projFiles"
#check images
eval "$imgPathes" | while read -d $'\0' png
do
name=`basename -s .png "$png"`
name=`basename -s @2x $name`
name=`basename -s @3x $name`
if grep -qhs "$name" $projFiles; then
echo "(used - $png)"
else
echo "!!!UNUSED - $png"
fi
done
@EdMcManusから提供された優れた回答を少し変更して、アセットカタログを利用するプロジェクトを処理しました。
#!/bin/bash
for i in `find . -name "*.imageset"`; do
file=`basename -s .imageset "$i"`
result=`ack -i "$file" --ignore-dir="*.xcassets"`
if [ -z "$result" ]; then
echo "$i"
fi
done
私は実際にはbashスクリプトを作成していないので、ここで改善すべき点がある場合は(おそらく)コメントでお知らせください。更新します。
私はluaスクリプトを書きましたが、仕事でそれを共有したので共有できるかわかりませんが、うまくいきます。基本的にはこれを行います:
ステップ1-静的画像参照(簡単なビット、他の回答でカバー)
ステップ2-動的画像参照(楽しいビット)
次に、どちらの検索でも見つからなかったものをすべて削除します。
最悪のケースは、サーバーから取得されたイメージ名が処理されないことです。これを処理するために、この検索にサーバーコードを含めます。
Xcode用のFauxPas Appを試すことができます。不足している画像や、Xcodeプロジェクトに関連する他の多くの問題/違反を発見するのは本当に良いことです。
他の回答を使用すると、これは2つのディレクトリの画像を無視し、pbxprojまたはxcassetsファイルで画像の出現を検索しない方法の良い例です(アプリアイコンとスプラッシュスクリーンに注意してください)。--ignore-dir = *。xcassetsの*をディレクトリに一致するように変更します。
#!/bin/bash
for i in `find . -not \( -path ./Frameworks -prune \) -not \( -path ./Carthage -prune \) -not \( -path ./Pods -prune \) -name "*.png" -o -name "*.jpg"`; do
file=`basename -s .jpg "$i" | xargs basename -s .png | xargs basename -s @2x | xargs basename -s @3x`
result=`ack -i --ignore-file=ext:pbxproj --ignore-dir=*.xcassets "$file"`
if [ -z "$result" ]; then
echo "$i"
fi
done
私はこのフレームワークを使用しました:-
http://jeffhodnett.github.io/Unused/
うまくいきます!問題が発生したのは、画像名がサーバーからのものである場合と、画像アセット名がアセットフォルダー内の画像名と異なる場合の2箇所のみです...
http://jeffhodnett.github.io/Unused/を使用して、未使用のイメージを見つけます。
未使用の画像を特定するPythonスクリプトを作成しました:'unused_assets.py' @ gist。次のように使用できます。
python3 unused_assets.py '/Users/DevK/MyProject' '/Users/DevK/MyProject/MyProject/Assets/Assets.xcassets'
スクリプトを使用するためのいくつかのルールを次に示します。
最初のバージョンの制限:
私はフィードバックに基づいて、時間をかけてそれを改善しようとしますが、最初のバージョンはほとんどの人にとって良いはずです。
コードの下を見つけてください。重要な各ステップに適切なコメントを追加したので、コードは自明です。
# Usage e.g.: python3 unused_assets.py '/Users/DevK/MyProject' '/Users/DevK/MyProject/MyProject/Assets/Assets.xcassets'
# It is important to pass project folder path as first argument, assets folder path as second argument
# It is assumed that all the images are maintained within Assets.xcassets folder and are used either within swift files or within storyboards
"""
@author = "Devarshi Kulshreshtha"
@copyright = "Copyright 2020, Devarshi Kulshreshtha"
@license = "GPL"
@version = "1.0.1"
@contact = "kulshreshtha.devarshi@gmail.com"
"""
import sys
import glob
from pathlib import Path
import mmap
import os
import time
# obtain start time
start = time.time()
arguments = sys.argv
# pass project folder path as argument 1
projectFolderPath = arguments[1].replace("\\", "") # replacing backslash with space
# pass assets folder path as argument 2
assetsPath = arguments[2].replace("\\", "") # replacing backslash with space
print(f"assetsPath: {assetsPath}")
print(f"projectFolderPath: {projectFolderPath}")
# obtain all assets / images
# obtain paths for all assets
assetsSearchablePath = assetsPath + '/**/*.imageset' #alternate way to append: fr"{assetsPath}/**/*.imageset"
print(f"assetsSearchablePath: {assetsSearchablePath}")
imagesNameCountDict = {} # empty dict to store image name as key and occurrence count
for imagesetPath in glob.glob(assetsSearchablePath, recursive=True):
# storing the image name as encoded so that we save some time later during string search in file
encodedImageName = str.encode(Path(imagesetPath).stem)
# initializing occurrence count as 0
imagesNameCountDict[encodedImageName] = 0
print("Names of all assets obtained")
# search images in swift files
# obtain paths for all swift files
swiftFilesSearchablePath = projectFolderPath + '/**/*.swift' #alternate way to append: fr"{projectFolderPath}/**/*.swift"
print(f"swiftFilesSearchablePath: {swiftFilesSearchablePath}")
for swiftFilePath in glob.glob(swiftFilesSearchablePath, recursive=True):
with open(swiftFilePath, 'rb', 0) as file, \
mmap.mmap(file.fileno(), 0, access=mmap.ACCESS_READ) as s:
# search all the assests within the swift file
for encodedImageName in imagesNameCountDict:
# file search
if s.find(encodedImageName) != -1:
# updating occurrence count, if found
imagesNameCountDict[encodedImageName] += 1
print("Images searched in all swift files!")
# search images in storyboards
# obtain path for all storyboards
storyboardsSearchablePath = projectFolderPath + '/**/*.storyboard' #alternate way to append: fr"{projectFolderPath}/**/*.storyboard"
print(f"storyboardsSearchablePath: {storyboardsSearchablePath}")
for storyboardPath in glob.glob(storyboardsSearchablePath, recursive=True):
with open(storyboardPath, 'rb', 0) as file, \
mmap.mmap(file.fileno(), 0, access=mmap.ACCESS_READ) as s:
# search all the assests within the storyboard file
for encodedImageName in imagesNameCountDict:
# file search
if s.find(encodedImageName) != -1:
# updating occurrence count, if found
imagesNameCountDict[encodedImageName] += 1
print("Images searched in all storyboard files!")
print("Here is the list of unused assets:")
# printing all image names, for which occurrence count is 0
print('\n'.join({encodedImageName.decode("utf-8", "strict") for encodedImageName, occurrenceCount in imagesNameCountDict.items() if occurrenceCount == 0}))
print(f"Done in {time.time() - start} seconds!")
FengNiaoを試すこともお勧めします。