文章转自:https://blog.coding.net/blog/statistics-of-IOS-project-pictures

iOS项目统计图片使用情况

随着项目开发推进和版本迭代,项目中总会存在一些无效的图片资源,这些无效图片往往会增加编译成本和包的大小。

一个普通的iOS工程会有大约三分之一的图片是未使用的。

常用的方法有:

1,利用工具;

2,利用脚本;

3,添加图片时候写图片名称的代码;

脚本&工具的原理大概是这样,在工程中搜图片名称,如果没有使用这个图片名称的话,则认为这张图片没有被使用并列举出来。这种做法不太精准:

1,遇到用imageview做动画(即imageView.animationImages)时候,一般开发人员都会喜欢用for循环加入所有图片,这样就会导致已使用图片被列举出来;

2,使用不同资源包时候,如果两个资源包有相同名称,但是有个资源包中的图片没被使用,这样就会导致未被使用的没列举出来;

诸如此类情况有很多。有人会说用第三种方法,但是手动添加这样比较费时,即下面这种场景:

例如,我们想跟踪在程序中每一个view controller展示给用户的次数:当然,我们可以在每个view controller的viewDidAppear中添加跟踪代码;但是这太过麻烦,需要在每个view controller中写重复的代码。创建一个子类可能是一种实现方式,但需要同时创建UIViewController, UITableViewController, UINavigationController及其它UIKit中view controller的子类,这同样会产生许多重复的代码。

上面一段是Method Swizzling中开篇的描述,确实人工手动添加难免会有漏掉,那么就要用苹果自带的方法集中处理。

我们可以通过Method Swizzling修改UIImage的调用方法,在UIImage中添加打印使用图片(或者路径)的方法,然后写到一个文件里,在项目结束时候将没有出现在文件中的图片删除即可(可以采用脚本删除,便捷准确)。

这种情况下,我们就可以写出如下Method Swizzling,如在代码所示:


#import "ADeanImage+Hook.h"
#import <objc/objc.h>
#import <objc/runtime.h>

@implementation UIImage (Hook)

+ (void)initialize
{
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        [self adeanImageHook];
    });
}

+ (void)adeanImageHook
{
    [self imageNameHook];
}

+ (void)imageNameHook  // 类方法调用方式
{
    Class class = object_getClass((id)self);
    SEL originalSelector = @selector(imageNamed:);
    SEL swizzledSelector = @selector(adean_imageNamed:);

    Method originalMethod = class_getClassMethod(class, originalSelector);
    Method swizzledMethod = class_getClassMethod(class, swizzledSelector);
    
    BOOL didAddMethod = class_addMethod(class, originalSelector, method_getImplementation(swizzledMethod), method_getTypeEncoding(swizzledMethod));
    if (didAddMethod)
    {
        class_replaceMethod(class, swizzledSelector, method_getImplementation(originalMethod), method_getTypeEncoding(originalMethod));
    }
    else
    {
        method_exchangeImplementations(originalMethod, swizzledMethod);
    }
}

+ (UIImage *)adean_imageNamed:(NSString *)name
{
    UIImage *image = [self adean_imageNamed:name];
    [self printImageNameToLocalWithImageName:name];
    return image;
}

+ (void)printImageNameToLocalWithImageName:(NSString *)name
{
#ifdef ADeanForTest
    {
        // 打印图片地址
        ADeanLog(@"adean_msg:  imagefile %@", IMAGEFILEFILE);
        FILE *fp;
        const char *imageFilePath =[IMAGEFILEFILE UTF8String];
        const char *cImageName = [[NSString stringWithFormat:@"%@\n", name] UTF8String];
        /*打开文件*/
        if((fp = fopen(imageFilePath, "a")) == NULL)
        {
            ADeanLog("文件打开出错,请检查文件是否存在\n");
        }
        else
        {
        }
        fputs(cImageName,fp);
        fclose(fp);
    }
#endif
}

这样只要在Appdelegate启动时候调用下[UIImage initialize]就可以将所有用到imageNamed:的图片都打印出来。
如果需要打印所有已使用图片,只需要将UIImage中所有的类方法和实例方法都Method Swizzling下。这样项目测试一遍就可以将所有已使用图片存到一张图片清单上,只要在用脚本语言删除项目中没在图片清单上的图片即可。


注:

中文版的《Objective-C Runtime 运行时之四:Method Swizzling》《Method Swizzling》漏掉了原著中的一段代码注释:

 // When swizzling a class method, use the following:      
 // Class class = object_getClass((id)self);
 // ...
 // Method originalMethod = class_getClassMethod(class, originalSelector);
 // Method swizzledMethod = class_getClassMethod(class, swizzledSelector);

<!--
4, AOP
-->




by Adorable Dean

at Nanjing, Jiangsu, China



利益相关:本篇文章所有涉及到的软件均为笔者日常所用工具,无任何广告费用。



参考文章:

如何删除xcode项目中不再使用的图片资源

有快捷的办法找到并删除 Xcode 工程中没用到的图片吗?
<!--
Method Swizzling和AOP(面向切面编程)实践

Aspects iOS的AOP面向切面编程的库
-->
Method Swizzling

Objective-C Runtime 运行时之四:Method Swizzling

Method Swizzling


CODING
3.3k 声望4k 粉丝

CODING 是腾讯云旗下一站式 DevOps 研发管理平台,向广大开发者及企业研发团队提供代码托管、项目协同、测试管理、持续集成、制品库、持续部署、云原生应用管理 Orbit、团队知识库等系列工具产品,支持 SaaS 模式...