打造一個頭文件引用修復(fù)工具(修復(fù)引用文件路徑為絕對路徑)

前言

由于Xcode的習(xí)慣欣范,很多OC代碼中.h文件引用都是只寫文件的,因?yàn)閄code會自動查找該文件的真實(shí)位置再傳遞給編譯器編譯,但這種做法有個限制,就是必須把.h文件引用到項目中,不然會找到,筆者的問題也就源于此,出于個人習(xí)慣,我不喜歡把不需要修改的文件引用到項目中,特別是編譯好的庫,一般情況下都是只引用.a文件,然后包含一個頭文件全部搞掂,即方便后期維護(hù)第三方庫,也方便文件管理,鑒于手動修改的文件實(shí)在太多了,這種沒含量的浪費(fèi)時間行為,還是交給CPU吧,于是便有了此文.

(特別說明,此工具的作用是把#import "header.h",擴(kuò)展為#import "../../include/header.h"的形式,如果沒這個需求就不用向下看了)

正文

假設(shè)源引用是#import "header.h",然后該文件放在上兩層的include目錄中(也就是../../include/header.h),先整理一下思路,要找到.h文件,第一種是暴力法,枚舉整個項目目錄,把找到的文件填充進(jìn)去,但感覺不是很好(感覺會有隱性BUG),第二種是先列舉所有可用文件列表,再從列表中匹配,這種方法可自定義程度高,本文采用此法.

進(jìn)行項目目錄,用命令行find . -name "*.h">~/Desktop/1.txt && find . -name "*.m">>~/Desktop/1.txt把所有可能的文件生成列表(若有其它格式,繼續(xù)添加,如.mm),打開.txt./替換為完整的路徑,然后把文本拆解為單行的數(shù)組,也就是完整的文件路徑,對每個文件進(jìn)行讀取,查找引用,替換引用,重新保存,過程如下:

  • 1.查找源文件目錄中是否存在引用文件,若有,則優(yōu)先使用.
  • 2.查找子目錄中是否存在引用文件,若有,則優(yōu)先使用.
  • 3.如源文件目錄和子目錄都找不到,則搜索切換到父目錄重新執(zhí)行,若枚舉完所有路徑都找不到,那就寫入出錯日志(代碼中未實(shí)現(xiàn),可自行添加).

代碼如下,有什么疑問歡迎和我交流.

@interface SCCodeHelper : NSObject
+ (void)fixHeaderWithSourceFiles: (NSArray *)sourceFiles; // 參數(shù)為可用的文件列表
@end

// SCModel為一個簡易模型轉(zhuǎn)換對象,可在我的github找到
@interface SCCoderFixImportHeaderInfo : SCModel
@property (nonatomic, strong) NSString *codeFile;
@property (nonatomic, strong) NSMutableString *codeString;

@property (nonatomic, strong) NSArray *validHeaders;
@property (nonatomic, strong) NSString *originImportLine;

@property (nonatomic, strong, readonly) NSString *headerFileName;
@property (nonatomic, strong, readonly) NSString *codeFileDir;
@property (nonatomic, strong, readonly) NSString *codeFileName;
@end

@implementation SCCoderFixImportHeaderInfo
- (void)setValidHeaders:(NSArray *)validHeaders
{
    _validHeaders = validHeaders;
    _headerFileName = [_validHeaders.firstObject lastPathComponent];
}

- (void)setCodeFile:(NSString *)codeFile
{
    _codeFile = codeFile;
    _codeFileDir = [_codeFile regexpReplace:@"/[^/]+$" replace:@""];
    _codeFileName = [_codeFile lastPathComponent];
}
@end

@implementation SCCodeHelper
+ (void)fixHeaderWithSourceFiles: (NSArray *)sourceFiles
{
    NSArray *ebx = sourceFiles;
    
    SCCoderFixImportHeaderInfo *info = NewClass(SCCoderFixImportHeaderInfo);
    
    for (NSString *ecx in ebx)
    {
        if (0 == ecx.length) continue;
        
        NSMutableString *code = [NSMutableString stringWithContentsOfFile:ecx encoding:NSUTF8StringEncoding error:NULL];
        if (0 == code.length) continue;
        
        NSMutableDictionary *imports = [self getImports:code];
        if (0 == imports.count) continue;
        
        for (NSString *file in imports.allKeys)
        {
            NSArray *finds = [self find:file map:sourceFiles];
            if (0 == finds.count) continue;
            
            info.codeFile = ecx;
            info.codeString = code;
            info.validHeaders = finds;
            info.originImportLine = imports[file];
            
            BOOL state = [self fixCodeWithModel:info fbackLevel:0];
            if (state) [code writeToFile:ecx atomically:YES encoding:NSUTF8StringEncoding error:NULL];
            BreakPointHere;
        }
        
        BreakPointHere;
    }
}

+ (BOOL)fixCodeWithModel: (SCCoderFixImportHeaderInfo *)info fbackLevel: (NSUInteger)fbackLevel
{
    NSString *codeFileName = info.codeFileName;
    NSString *headerFileName = info.headerFileName;
    NSString *originImportLine = info.originImportLine;
    NSString *codeFileDir = info.codeFileDir;
    NSMutableString *codeString = info.codeString;
    NSArray *validHeaders = info.validHeaders;
    
    // 跳過絕對路徑
    if (StringHasSubstring(originImportLine, @"/")) return NO;
    
    BOOL codeChanged = NO;
    BOOL result = NO;
    
    if (fbackLevel)
    {
        for (NSUInteger a = 0; a < fbackLevel; ++a)
        {
            codeFileDir = [codeFileDir regexpReplace:@"/[^/]+$" replace:@""];
        }
        BreakPointHere;
    }
    
    {
        // 看看同目錄
        NSString *ebx = [NSString stringWithFormat:@"%@/%@", codeFileDir, headerFileName];
        for (NSString *eax in validHeaders)
        {
            if (NO == IsSameString(eax, ebx)) continue;
            
            NSString *ecx = @"";
            if (fbackLevel)
            {
                for (NSUInteger a = 0; a < fbackLevel; ++a)
                {
                    ecx = [NSString stringWithFormat:@"../%@", ecx];
                }
            }
            NSString *line = [NSString stringWithFormat:@"#import \"%@%@\"", ecx, headerFileName];
            
            if (NO == StringHasSubstring(originImportLine, line))
            {
                MLog(@"src: %@", codeFileName);
                MLog(@"fix: %@", originImportLine);
                MLog(@"to : %@", line);
                MLog(@"=========================================================");
                [codeString replaceOccurrencesOfString:originImportLine withString:line options:0 range:NSMakeRange(0, codeString.length)];
                codeChanged = YES;
            }
            
            result = YES;
            break;
        }
        
        if (result) return codeChanged;
    }
    
    // 看看子目錄
    {
        for (NSString *eax in validHeaders)
        {
            if (NO == StringHasSubstring(eax, codeFileDir)) continue;
            
            NSString *buffer = [eax stringByReplacingOccurrencesOfString:codeFileDir withString:@""];
            buffer = [buffer regexpReplace:@"^/" replace:@""];
            
            NSString *ecx = @"";
            if (fbackLevel)
            {
                for (NSUInteger a = 0; a < fbackLevel; ++a)
                {
                    ecx = [NSString stringWithFormat:@"../%@", ecx];
                }
            }
            
            NSString *line = [NSString stringWithFormat:@"#import \"%@%@\"", ecx, buffer];
            
            if (NO == StringHasSubstring(originImportLine, line))
            {
                MLog(@"src: %@", codeFileName);
                MLog(@"fix: %@", originImportLine);
                MLog(@"to : %@", line);
                MLog(@"=========================================================");
                [codeString replaceOccurrencesOfString:originImportLine withString:line options:0 range:NSMakeRange(0, codeString.length)];
                codeChanged = YES;
            }
            
            result = YES;
            break;
        }
        
        if (result) return codeChanged;
    }
    
    // 看看上層目錄
    {
        if (NO == [codeFileDir isEqualToString:@"/"])
        {
            codeChanged = [self fixCodeWithModel:info fbackLevel:fbackLevel+1];
            return codeChanged;
        }
    }
    
    LogAnything(codeFileDir);
    LogAnything(info.validHeaders);
    BreakPointHere;
    return NO;
}

+ (NSMutableArray *)find: (NSString *)file map: (NSArray *)map
{
    NSMutableArray *result = NewMutableArray();
    
    for (NSString *name in map)
    {
        NSString *eax = [NSString stringWithFormat:@"/%@", file];
        if ([name hasSuffix:eax])
        {
            [result addObject:name];
        }
    }
    
    if (0 == result.count) return nil;
    return result;
}

+ (NSMutableDictionary *)getImports: (NSString *)code
{
    NSArray *imps = [code regexpMatch:@"[\\r\\n]\\s*#import\\s+\\x22[^\\x22]+\\x22"];
    
    NSMutableDictionary *result = nil;
    if (imps.count) result = NewMutableDictionary();
    
    for (NSString *eax in imps)
    {
        NSString *file = [eax regexpMatch:@"\\x22[^\\x22]+\\x22"][0];
        file = [file stringByReplacingOccurrencesOfString:@"\"" withString:@""];
        
        result[file] = [eax regexpReplace:@"[\\r\\n]+" replace:@""];
    }
    
    return result;
}
@end
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,941評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件蚯撩,死亡現(xiàn)場離奇詭異,居然都是意外死亡烛占,警方通過查閱死者的電腦和手機(jī)胎挎,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,397評論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來忆家,“玉大人犹菇,你說我怎么就攤上這事⊙壳洌” “怎么了项栏?”我有些...
    開封第一講書人閱讀 165,345評論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長蹬竖。 經(jīng)常有香客問我沼沈,道長,這世上最難降的妖魔是什么币厕? 我笑而不...
    開封第一講書人閱讀 58,851評論 1 295
  • 正文 為了忘掉前任列另,我火速辦了婚禮,結(jié)果婚禮上旦装,老公的妹妹穿的比我還像新娘页衙。我一直安慰自己,他們只是感情好阴绢,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,868評論 6 392
  • 文/花漫 我一把揭開白布店乐。 她就那樣靜靜地躺著,像睡著了一般呻袭。 火紅的嫁衣襯著肌膚如雪眨八。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,688評論 1 305
  • 那天左电,我揣著相機(jī)與錄音廉侧,去河邊找鬼。 笑死篓足,一個胖子當(dāng)著我的面吹牛段誊,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播栈拖,決...
    沈念sama閱讀 40,414評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼连舍,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了涩哟?” 一聲冷哼從身側(cè)響起索赏,我...
    開封第一講書人閱讀 39,319評論 0 276
  • 序言:老撾萬榮一對情侶失蹤诗鸭,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后参滴,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體强岸,經(jīng)...
    沈念sama閱讀 45,775評論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,945評論 3 336
  • 正文 我和宋清朗相戀三年砾赔,在試婚紗的時候發(fā)現(xiàn)自己被綠了蝌箍。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,096評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡暴心,死狀恐怖妓盲,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情专普,我是刑警寧澤悯衬,帶...
    沈念sama閱讀 35,789評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站檀夹,受9級特大地震影響筋粗,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜炸渡,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,437評論 3 331
  • 文/蒙蒙 一娜亿、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧蚌堵,春花似錦买决、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,993評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至泻蚊,卻和暖如春躲舌,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背藕夫。 一陣腳步聲響...
    開封第一講書人閱讀 33,107評論 1 271
  • 我被黑心中介騙來泰國打工孽糖, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留枯冈,地道東北人毅贮。 一個月前我還...
    沈念sama閱讀 48,308評論 3 372
  • 正文 我出身青樓,卻偏偏與公主長得像尘奏,于是被迫代替她去往敵國和親滩褥。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,037評論 2 355

推薦閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理炫加,服務(wù)發(fā)現(xiàn)瑰煎,斷路器铺然,智...
    卡卡羅2017閱讀 134,659評論 18 139
  • 1. Java基礎(chǔ)部分 基礎(chǔ)部分的順序:基本語法,類相關(guān)的語法酒甸,內(nèi)部類的語法魄健,繼承相關(guān)的語法,異常的語法插勤,線程的語...
    子非魚_t_閱讀 31,639評論 18 399
  • 頭文件引用一般都會隨著項目規(guī)模變大而可讀性變差沽瘦。當(dāng)大部分精力花費(fèi)在業(yè)務(wù)上往往容易忽視頭文件的使用和規(guī)范。整理下常見...
    Mr_GaoYu閱讀 12,319評論 5 14
  • 為什么很多內(nèi)置類如UITableView的delegate屬性都是assign而不是retain? 所有的引用計數(shù)...
    煙雨平生花飛舞閱讀 1,193評論 0 3
  • 字:防~生活處處有騷擾农尖?感覺防不勝防析恋。 文:近期我賬號辦了封停,因?yàn)槭謾C(jī)與卡出問題了游子這么小心謹(jǐn)慎盛卡?還不算吧助隧,當(dāng)...
    老區(qū)游子閱讀 342評論 0 1