发现工程中的bundle中有很多图片是重复,想把重复的图片找出来,删掉,辅助瘦包。
创建了一个单独的工程,将bundle文件拷贝到工程中。查了一下,可以获取图片信息进行对比的算法有三个,分别是PSNR峰值信噪比算法,感知哈希算法和计算特征点算法,只找到了OC的感知哈希算法代码,于是就用感知哈希算法进行对比。
开始时没有考虑性能和内存问题,就直接写了两个for循环,将第一张图片和后面所图片进行,对比。将第二张图片和后面所有图片进行对比,依次进行,直到对比完成。对比过程中,遇到相似的图片,用字典记录两张图片名,保存到内存数组中,全部对比结束,将结果以plist文件的形式写入到沙盒中。在模拟器运行代码,运行后,CPU利用率固定在100%,内存利用率持续攀升,最后崩溃。
考虑内存和性能问题,引入自动释放池和多线程,两层for循环都放在自动释放池中,第二次for循环,逻辑判断代码放到dispatch_async下,继续运行。运行时,CPU利用率大概维持在600%,内存稳定在600M左右,可以执行完成不崩溃,但是没有写入plist文件。分析发现使用多线程的原因,写入操作不是在多线程执行完成后执行的,而是多线程创建完成后执行。
和小伙伴分析代码,发现了一些问题,一一改进。bundle文件夹下有文件夹和图片两种模式,通过一次pathsForResourcesOfType只取到了图片,未取到文件下的图片,因此做调整,直接取图片,再取bundle文件夹下的文件夹,再遍历取到的文件夹中的图片。第二层for循环对比时重复进行NSData转image的操作,进行优化,在for循环对比前将所有图片数据处理完成,使用字典存储,for循环对比时对比字典中存储的数据。还有,如果两张图片完全一样,则两张图片的NSData数据的MD5字符串是完全一样的,因此for循环对比前先对比MD5,减少一部分对比操作。
以上优化完成后,重新执行,发现还有一点漏洞,写入数据完成后还执行了几次对比。原来是我使用信号量时,触发信号量的时机有问题,多线程不是顺序执行的,我判断两层for循环的索引值都是最大,判定为全部对比完成是错误的,考虑到数据量太大,初始时我也不知道对比次数,所以使用信号量这种方式保证多线程全部执行完再执行写入操作有瑕疵,所以改为dispatch_group方式,完美解决问题。
这次操作,让我加深了对沙盒文件存储,多线程相关的知识印象。
网友评论