基于Xcode8插件开发~一键检测处理头文件引用

Xcode8开放了新的一个Extension:Xcode Source Editor Extension,目的是让开发者可以正规的自主为IDE编写插件,虽然说系统现提供的功能还比较拮据,但是不妨碍我们了解和使用,本文主要介绍Xcode Source Editor Extension的功能,并演示一个简单的插件的实现~

一、实现功能

1.删除无用的类头文件,要求类名和文件名一致
2.删除重复导入的头文件,只保留一个

二、编写代码

1.新建项目,然后新建一个Target,类型选择Xcode Source Editor Extension,完成之后设置target的签名和项目的签名一致。


在New中选择Target

2.在info.plist中可以修改插件显示名称Bundle name和其它对Extension的设置。

插件的info.plist

3.系统默认为我们生成SourceEditorCommand文件,此处我们也可以在info里边修改配置项,类似于项目中系统生成的Main.storyboard。插件的重点基本在:

- (void)performCommandWithInvocation:(XCSourceEditorCommandInvocation *)invocation completionHandler:(void (^)(NSError * _Nullable nilOrError))completionHandler

用户调用我们的插件时,系统会回调这个方法,

XCSourceEditorCommandInvocation

Information about the source editor command that the user invoked, such as the identifier of the command, the text buffer on which the command is to operate, and whether the command has been canceled by Xcode or the user.

其中invocation.buffer是编辑器的全部文本

/** 当前编辑器的全部文件内容 */
@property (readonly, strong) NSMutableArray <NSString *> *lines;
/** 是当前选中的文本 */
@property (readonly, strong) NSMutableArray <XCSourceTextRange *> *selections;

我们在回调方法中编写如下代码:

源码图片一份,方便查看
    //headerDict存放文本中所有的头文件
    NSMutableDictionary <NSString*, NSNumber *>*headerDict = [NSMutableDictionary dictionary];
    //willCheckDict存放将要删除的头文件
    NSMutableDictionary <NSNumber*, NSString *>*willCheckDict = [NSMutableDictionary dictionary];
    
    //遍历编辑器每一行
    for (int idx = 0; idx < invocation.buffer.lines.count; idx++) {
        
        NSString *lineCode = invocation.buffer.lines[idx];
        
        //若willCheckDict文件不为空,则进行是否使用了该头文件的判断
        if (willCheckDict.count > 0) {
            [willCheckDict enumerateKeysAndObjectsUsingBlock:^(NSNumber * _Nonnull key, NSString * _Nonnull checkString, BOOL * _Nonnull stop) {
                if ([lineCode containsString:checkString]) {
                    if (![lineCode containsString:@"#import"]) {
                        if ([headerDict[checkString] isEqualToNumber: @1]) {
                            //若使用了该头文件,则从willCheckDict字典中提出该项
                            [willCheckDict removeObjectForKey:key];
                            //同时设置该头文件已经检查过,若后续仍出现该头文件,则可以进行删除
                            headerDict[checkString] = @0;
                        }
                    }
                }
            }];

        }
        
        //检测代码是否含有#import为头文件标志;+号我们认为是类扩展的标志
        if ([lineCode containsString:@"#import"] && ![lineCode containsString:@"+"]) {
            //解析获取类名
            NSRange range1 = [lineCode rangeOfString:@"\""];
            NSRange range2 = [lineCode rangeOfString:@"\"" options:NSBackwardsSearch];
            NSRange zeroRange = NSMakeRange(0, 0);
            
            if (!(NSEqualRanges(range1, zeroRange) || NSEqualRanges(range2, zeroRange))) {
                NSRange findRange = NSMakeRange(range1.location + 1, range2.location - range1.location - 3);
                NSString *classString = [lineCode substringWithRange:findRange];
                willCheckDict[@(idx)] = classString;
                headerDict[classString] = @1;
            }
        }
    }
    
    
    //取出需要删除的行
    NSMutableIndexSet *index = [NSMutableIndexSet indexSet];
    [willCheckDict.allKeys enumerateObjectsUsingBlock:^(NSNumber * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
        [index addIndex:obj.integerValue];

    }];
    
    //删除不符合条件的行
    [invocation.buffer.lines removeObjectsAtIndexes:index];
    
    //通知系统完成
    completionHandler(nil);
三、测试结果

1.运行,选择Xcode8

command+r运行插件

2.可以看见灰色的Xcode实例。随便选择一个项目打开

测试的Xcode,用于区别正式的Xcode

3.测试。测试文件中含有未使用的头文件和冗余的头文件

处理前代码

4.Editor中选择插件运行

不出意外Editor菜单最底下一栏,此处名字可以在info.plist修改

5.检验运行结果

处理后代码

啦啦啦,多余的头文件已经被成功检测到并且移除了了~

四、总结

至此,我们完成并测试通过了一个简单的Xcode插件的编写。主要目的是简单了解和使用Xcode8的插件,如果觉得有用,可以找到product里边的文件复制出来打开,然后在系统设置辅助功能中启用,最后在Xcode中绑定快捷键即可食用。当然,功能十分简陋,还请大神勿怪~

不足:受限于系统现有API,运行插件时,只能获取到当前编辑的文件,无法获取整个项目文件来分析,故很多功能暂时无法实现,如支持更加智能的检测等等,以后系统若能提供项目空间的文件访问和GUI支持,则插件可以发挥更大作用~

github地址:https://github.com/yate1996/XcodeAutoImportExtension

知识链:
WWDC2016
iOS 10 Day By Day: Xcode Source Editor Extensions
使用 Xcode Source Editor Extension开发Xcode 8 插件

欢迎加群讨论其它~:578874451

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,905评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,140评论 2 379
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,791评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,483评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,476评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,516评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,905评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,560评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,778评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,557评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,635评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,338评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,925评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,898评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,142评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,818评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,347评论 2 342

推荐阅读更多精彩内容