關(guān)于清理項(xiàng)目資源圖片
很長(zhǎng)一段時(shí)間,我們所做的APP的包都很大,90多M,plus上也有過(guò)100多M,但是,現(xiàn)在的包就50+M,期間有三次比較大的瘦身工程,第一次,是剛換leader的時(shí)候,大約是16年中,第二次是16年末前后大約2個(gè)項(xiàng)目周期期間,第三次是17年中。
第一次瘦身
16年6月之后的兩個(gè)項(xiàng)目周期,也就是剛開(kāi)始處理項(xiàng)目,我們做的活兒并不多
- 一是處理代碼里打警告,這些警告包括:1-方法廢棄警告;2 - 類(lèi)型轉(zhuǎn)換警告;3 - unsed警告等。
- 二是刪除一些重復(fù)圖片,當(dāng)時(shí)用的是PhotoSweepper,軟件只能查出來(lái)重復(fù)的圖片,但是刪的時(shí)候還是要注意留誰(shuí),建議把不準(zhǔn)的看下重復(fù)圖片的像素。
注意處理警告的時(shí)候,有些類(lèi)型轉(zhuǎn)換或者present廢棄的情況要自己查驗(yàn),很有可能出bug的,要 處理好上下文!
這次瘦身讓項(xiàng)目看得清爽了一點(diǎn),畢竟少了幾千的警告!!
第二次瘦身
因?yàn)槲腋鷏eader挨著,平時(shí)做的研究性(雜活兒)比較多,我不是處女座,但是我看不慣項(xiàng)目代碼的凌亂,我們都知道一點(diǎn),項(xiàng)目包再大,只要它能正常運(yùn)行,就不會(huì)有人找你麻煩,但是如果你動(dòng)了代碼,出了問(wèn)題,那么罪當(dāng)然是你的了。我的leader不贊成我刪代碼,但是也沒(méi)有阻止我!于是,我開(kāi)始第一次刪除代碼(一些陳舊廢棄的代碼,但是寫(xiě)這個(gè)的人早就離職了,管這個(gè)的產(chǎn)品可能也離職了,我遇到過(guò)最恐怖的情況,開(kāi)發(fā),產(chǎn)品,測(cè)試,后端懂這塊邏輯的都離職了···)。
16年末是我剛接手項(xiàng)目(姑且叫A)里一整個(gè)模塊的時(shí)候,姑且叫模塊B,項(xiàng)目B之余A可以說(shuō)是完全獨(dú)立的,當(dāng)在登錄的時(shí)候,會(huì)根據(jù)賬號(hào)權(quán)限,如果有B的權(quán)限,會(huì)提示去A還是B。項(xiàng)目B的代碼是14年那種很古老的代碼... 我這次主要?jiǎng)h的是B里那期提了需求的代碼,我會(huì)去梳理邏輯,進(jìn)而會(huì)發(fā)現(xiàn)無(wú)用的類(lèi)。下面說(shuō)下我的經(jīng)驗(yàn):
- 我們可以在項(xiàng)目里加個(gè)類(lèi)目,這樣可以在點(diǎn)擊到哪個(gè)頁(yè)面就打印當(dāng)前是哪個(gè)類(lèi),當(dāng)然我們得有足夠進(jìn)入所有頁(yè)面的賬號(hào),可以問(wèn)產(chǎn)品問(wèn)測(cè)試~~當(dāng)然你也可以自己捋。
#import "UIViewController+Tracking.h"
#import <objc/runtime.h>
@implementation UIViewController (Tracking)
+ (void)load {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
Class class = [self class];
swizzMethod(class, @selector(viewWillAppear:), @selector(fang_viewWillAppear:));
swizzMethod(class, @selector(viewDidAppear:), @selector(fang_viewDidAppear:));
});
}
static void swizzMethod(Class class, SEL originalSelector, SEL swizzledSelector) {
Method originalMethod = class_getInstanceMethod(class, originalSelector);
Method swizzledMethod = class_getInstanceMethod(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);
}
}
#pragma mark - Method Swizzling
- (void)fang_viewWillAppear:(BOOL)animated {
[self fang_viewWillAppear:animated];
// NSLog(@"viewWillAppear:%@", self);
}
- (void)fang_viewDidAppear:(BOOL)animated {
[self fang_viewDidAppear:animated];
// NSLog(@"[viewDidAppear]:%@", self);
BOOL exclude = YES;
for (NSString *classString in [self excludeArray]) {
if ([self isKindOfClass:NSClassFromString(classString)]) {
exclude = NO;
break;
}
}
if (exclude) {
NSLog(@"[搜房幫]:%@", [self class]);
}
}
- (NSArray *)excludeArray {
NSArray *array = @[@"UINavigationController",
@"UIAlertController",
@"FangPageViewController",
@"UIInputWindowController",
@"UICompatibilityInputViewController",
@"UIPageViewController"];
return array;
}
@end
如上,當(dāng)我們要重構(gòu)這個(gè)頁(yè)面的時(shí)候,跟這個(gè)頁(yè)面有關(guān)的,controller,cell,model,viewmodel就都可以刪了,甚至沒(méi)用的圖片
*人有多大膽,地有多大產(chǎn),哪怕是個(gè)小需求,更改一點(diǎn)東西,你也可以把整塊刪了,自己寫(xiě),反正測(cè)試會(huì)測(cè)的,以后你是想繼續(xù)糊窗戶紙還是住小洋房就看你懶不懶了。
*假如我們這個(gè)類(lèi)是不用的,我們可以先注釋掉這個(gè)類(lèi),command+b,那么接下來(lái)你要處理的就是一層層的警告,先把別的類(lèi)引用的這個(gè)不用類(lèi)的import注釋掉,處理完這層警告后,可以繼續(xù)刪除和他相關(guān)的cell什么的,同樣是先注釋再編譯,再刪除??偨Y(jié)下來(lái)就是
*注釋本類(lèi)(C)---->注釋引用C的頭文件---->刪除只與C有關(guān)的類(lèi)---->刪除C---->全局搜索引用C的類(lèi)---->確認(rèn)是否有用,沒(méi)有按上循環(huán),有用刪除對(duì)C的引用
第三次瘦身
這次瘦身小了大約20M的包大小,這次跟第二次的方法基本一樣,有一點(diǎn)不同是,這次是刪頁(yè)面,比如,我們要?jiǎng)h“我的”這個(gè)頁(yè)面,要知道這個(gè)頁(yè)面有很多cell,點(diǎn)擊cell進(jìn)去又是很多cell,這時(shí)候我們要做的是從最里面的頁(yè)面往外刪除,按上邊的方法,切不可急躁。
這次刪除遇到個(gè)問(wèn)題就是,有些類(lèi)本身就是廢棄在項(xiàng)目里的,所以根本就沒(méi)引用??!我們知道我們刪除代碼的時(shí)候有1-move to trash 2- move reference,當(dāng)時(shí)打“前輩”估計(jì)就是選了2。。。他是多愛(ài)你···給你挖的坑!好在我們的項(xiàng)目模塊是分文件夾的,日積月累,盡管不那么整潔,但是還是能知道這個(gè)類(lèi)是不是可以刪了,所以?xún)牲c(diǎn)建議:
- 一是項(xiàng)目模塊分好文件夾
- 二是項(xiàng)目類(lèi)名要駝峰按模塊從大到小命名
這次瘦身還涉及到了一些非頁(yè)面類(lèi)模塊,比如網(wǎng)絡(luò)配置類(lèi),通知類(lèi),這每個(gè)公司都不太一樣,我們的老前輩,是在項(xiàng)目里建了個(gè)通知中心,每個(gè)接口對(duì)應(yīng)不通的通知名,這時(shí)候,要清理就比較麻煩了,項(xiàng)目越大越麻煩,如果你們項(xiàng)目分模塊,那么恭喜了~如果沒(méi)分,你就慢慢刪吧,從整理頁(yè)面通知開(kāi)始。如果分模塊了,你就可以整個(gè)模塊注釋?zhuān)邸?/p>
項(xiàng)目里還有一些重復(fù)的單例類(lèi),雖然這種情況不該發(fā)生,但是確實(shí)有很多類(lèi)似的工具類(lèi),后人不知道前輩已經(jīng)寫(xiě)好了,或者前輩寫(xiě)的不通用!好吧,我自己寫(xiě)一個(gè),那我也寫(xiě)一個(gè)···你懂的~~ 你可以把所有的頭文件都合并到另一個(gè)去,@implementation也如是,這時(shí)候優(yōu)先對(duì)待紅色警告,其次是黃色,類(lèi)似的合并,command + B,改項(xiàng)目里的被你剛剛刪除的那個(gè)方法!一個(gè)個(gè)改就好了~~
刪除資源圖片
鏈接:https://github.com/tinymind/LSUnusedResources
這個(gè)工具可以檢測(cè)出項(xiàng)目里很大一部分沒(méi)用的圖片或者重復(fù)的圖片,但是有bug
- 會(huì)閃退,大家可以自己改改里面的代碼,我們用的時(shí)候修改過(guò)一次,閃退很少
- 檢測(cè)出的有可能是有用的圖片,我遇到的一種情況是動(dòng)態(tài)圖片名字,比如圖片有normal(used_n_%@),high(used_h_%@...),諸如這種類(lèi)似的命名,就可能造成還在用而被你刪除的問(wèn)題。
使用

除了上邊的建議另外有幾點(diǎn):
- 建議所有的資源圖片都放到一個(gè)文件夾,分模塊放在子文件夾
- 圖片要讓設(shè)計(jì)(美工)上點(diǎn)心,別要一個(gè)給一個(gè),很多都重復(fù)了,要不開(kāi)發(fā)建個(gè)管理系統(tǒng),要不測(cè)試弄一個(gè),這個(gè)好很多
- 建議按view,model,viewmodel viewcontroller,vendor,framework等分好文件夾等
- 本來(lái)就是精簡(jiǎn)代碼,我卻BB了這么多,就是告訴大家,瘦身挺麻煩的,熟能生巧,膽子要大?。?!