基于Xcode8插件开发~一键检测处理头文件引用
Xcode8开放了新的一个Extension:Xcode Source Editor Extension,目的是让开发者可以正规的自主为IDE编写插件,虽然说系统现提供的功能还比较拮据,但是不妨碍我们了解和使用,本文主要介绍Xcode Source Editor Extension的功能,并演示一个简单的插件的实现~
一、实现功能
1.删除无用的类头文件,要求类名和文件名一致
2.删除重复导入的头文件,只保留一个
二、编写代码
1.新建项目,然后新建一个Target,类型选择Xcode Source Editor Extension,完成之后设置target的签名和项目的签名一致。

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

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

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

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

4.Editor中选择插件运行

5.检验运行结果

啦啦啦,多余的头文件已经被成功检测到并且移除了了~
四、总结
至此,我们完成并测试通过了一个简单的Xcode插件的编写。主要目的是简单了解和使用Xcode8的插件,如果觉得有用,可以找到product里边的文件复制出来打开,然后在系统设置辅助功能中启用,最后在Xcode中绑定快捷键即可食用。当然,功能十分简陋,还请大神勿怪~
不足:受限于系统现有API,运行插件时,只能获取到当前编辑的文件,无法获取整个项目文件来分析,故很多功能暂时无法实现,如支持更加智能的检测等等,以后系统若能提供项目空间的文件访问和GUI支持,则插件可以发挥更大作用~
知识链:
WWDC2016
iOS 10 Day By Day: Xcode Source Editor Extensions
使用 Xcode Source Editor Extension开发Xcode 8 插件
欢迎加群讨论其它~:578874451
基于Xcode8插件开发~一键检测处理头文件引用的更多相关文章
- ArcCore重构-头文件引用问题的初步解决
基于官方arc-stable-9c57d86f66be,AUTOSAR版本3.1.5 基本问题 1. 头文件引用混乱,所有头文件通过从搜索路径(-I)中引用,存在名称污染问题,需加入路径信息: ...
- vscode中c/c++头文件引用找不到飘红
正在进行 GTK 学习, 但是在 vscode GTK 的头文件找不到(头文件引用底下飘红, 逼死强迫症), 影响敲字键入速度. 解决一下该问题-- vscode中c/c++头文件引用找不到(#inc ...
- 一键生成JNI头文件方法二
经常使用java的同学一定都接触过JNI(Java Native Interface)吧.JNI为我们提供了java<---->C/C++之间的接口,使得我们可以在java中调用C程序,以 ...
- Object-c 语法 - 头文件引用(@class/#import/#include)
一. Objective-C 中 #import 和 #include 的区别 预编译指令 Objective-C:#import:由gcc编译器支持 C,C++:#include 在 Objecti ...
- C语言头文件引用
1,引用分为两种 firs:include<fileName.h> 引用系统头文件一般用<>. second:include"fileName.h" 引用自 ...
- vc++中 .H 头文件引用的顺序与符号关系
在使用 #include "math.h" 和 #include <math.h>时,引号 与尖括号的区别如下 此时math.h_1 在工程文件中 math.h_2 ...
- VS2010 正则批量替换头文件路径
最近在项目实践中,需要统一对工程头文件进行重构,具体要求是,将之前 #include "../../abc/def.h" 类似的头文件引用路径 替换为#include &q ...
- 系统头文件cmath,cstdlib报错
>C:\Program Files (x86)\Microsoft Visual Studio\\Community\VC\Tools\MSVC\\include\cstdlib(): erro ...
- 引用其他头文件时出现这种错误,莫名其妙,error C2065: “ColorMatrix”: 未声明的标识符
今天做项目时,直接拷贝了另一个工程里的头文件和源文件,然后运行时就出现这种问题,莫名其妙,在原程序里运行一点问题就没有,但是在新工程里就是error. >e:\c++\button_fly2\b ...
随机推荐
- hdu 5754 Life Winner Bo 博弈论
对于king:我是套了一个表. 如果起点是P的话,则是后手赢,否则前手赢. 车:也是画图推出来的. 马:也是推出来的,情况如图咯. 对于后:比赛时竟然推错了.QAQ最后看了题解:是个威佐夫博奕.(2, ...
- ural1521 War Games 2
War Games 2 Time limit: 1.0 secondMemory limit: 64 MB Background During the latest war games (this s ...
- fuel健康检查Heat失败的原因
service openstack-heat-engine restart chkconfig --level 2345 openstack-heat-engine on
- 密钥public/private key登陆linux
Public Key认证是什么这是一种认证方法,类似于常见的用户名密码认证方法.不同的是需要在客户端机器上保留一个很长很长的加密key,而在服务器端需要做出相应的配置.当客户端想要访问服务器时,服务器 ...
- strace 分析 跟踪 进程错误
strace是什么? 按照strace官网的描述, strace是一个可用于诊断.调试和教学的Linux用户空间跟踪器.我们用它来监控用户空间进程和内核的交互,比如系统调用.信号传递.进程状态变更等. ...
- eclipse java生成exe
eclipse导出jar文件再将它转换成exe可执行文件详解 关键字: 欢迎光临 此文章是为了帮助刚接触j2se或不懂如何打包jar文件的人而着笔,同时也是让自己的知识以文章的形式保存起来. 一.导出 ...
- [Asp.Net Core轻量级Aop解决方案]AspectCore Project 介绍
AspectCore Project 介绍 什么是AspectCore Project ? AspectCore Project 是适用于Asp.Net Core 平台的轻量级 Aop(Aspect- ...
- PHP安装插件方式
PHP安装插件方法主要有两种: 1.先安装相关的库,zlib.curl.xml等,然后在安装 php 时的 ./configure 中设置 --with-xxx(你需要的插件),三部曲安装即可. 2. ...
- 如何使用UDP进行跨网段广播(转)
源:如何使用UDP进行跨网段广播 广播域首先我们来了解一下广播域的概念.广播域是网络中能接收任一台主机发出的广播帧的所有主机集合.也就是说,如果广播域内的其中一台主机发出一个广播帧,同一广播域内所有的 ...
- Java使用POI实现数据导出excel报表
Java使用POI实现数据导出excel报表 在上篇文章中,我们简单介绍了java读取word,excel和pdf文档内容 ,但在实际开发中,我们用到最多的是把数据库中数据导出excel报表形式.不仅 ...