Answers:
对于未包含在项目中但只是在文件夹中徘徊的文件,您可以按
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使此过程非常快,但是如果此脚本频繁运行,则需要进行一些明显的优化。例如,如果您同时拥有视网膜/非视网膜资产,则此代码会检查每个基本名称两次。
#!/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的“ 未使用”的严重影响,但老实说,“未使用”的速度很慢,结果也不完全正确。因此,我进行了一些性能优化,搜索速度比未使用的要快。
我尝试了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
也许你可以试试苗条,做得像样。
更新:本着emcmanus的想法,我继续创建了一个小工具,没有任何确认,只是为了避免在计算机中进行其他设置。
只有这个脚本对我有用,它甚至可以处理文件名中的空格:
已更新以支持swift
文件和cocoapod
。默认情况下,它不包含Pods目录,并且仅检查项目文件。要同时检查Pods文件夹,请使用--pod
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脚本,我不确定是否可以共享它,因为我在工作中就做到了,但是效果很好。基本上,它是这样做的:
步骤一-静态图像引用(简单易用,其他答案涵盖)
第二步-动态图像引用(有趣的地方)
然后删除在任一搜索中未找到的内容。
最极端的情况是不处理来自服务器的图像名称。为了处理此问题,我们在此搜索中包括服务器代码。
您可以尝试Xcode的FauxPas App。在发现丢失的图像以及与Xcode项目相关的许多其他问题/违规行为方面,这样做非常好。
使用其他答案,这个例子很好地说明了如何忽略两个目录中的图像,以及如何不搜索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/查找未使用的图像。
我创建了一个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!")