PYJsonViewManager
示例
要运行示例项目,请首先将代码库克隆到本地,然后从 Example 目录运行 pod install
。
要求
安装
PYJsonViewManager 可通过 CocoaPods 获取。要安装它,只需将以下行添加到 Podfile 中
pod 'PYJsonViewManager'
作者
LiPengYue, [email protected]
许可证
PYJsonViewManager 在 MIT 许可证下可用。更多信息请参见 LICENSE 文件。
简介
描述
BaseJsonViewController
是一个用OC
编写的提供了搜索
、插入
、编辑
、查看路径
、复制json/value
等功能的Json
可视化编辑工具。
由于网络数据请求下来后,
App
端对Json
原数据的展示并不清晰。修改网络数据只能通过Charles
等抓包工具实现,受限太多,因此诞生了在App
端直接对Json
进行查看和修改的Json
视图工具:BaseJsonViewController
。后续会对
BaseJsonViewController
持续更新优化,欢迎大家使用。
主要功能
Json结构展示:
- 一键压缩/展开:点击
👀all
展开全部,点击🦆…
压缩全部(需要注意的是,如果进行了压缩,处在插入状态的cell将被删除)。 - 添加了层级的背景色、缩进等。默认最大展示6个层级,如果超过6个层级则跳转到新的页面进行展示。
- 对类型的区分:分为
Dictionary
Array
String
Number
。 - 支持展开与收起功能,若有子节点,则单击可以展开/收起。
- value的展示:一行cell的value默认最多展示两行。如果超过两行则压缩,并在底部展示。
搜索功能:
点击放大镜可以进入搜索界面
位置源码:在BaseJsonViewController
->BaseJsonViewMainView
->BaseJsonHeaderView
->BaseJsonViewSearchView
搜索关键词:输入关键词,会自动进行搜索。
精确搜索:如果选中精确搜索,搜索策略将从
containsString
变成isEqualToString
。注意:无论是否为精确搜索,都会区分大小写。
- 搜索编辑状态:如果选中【搜编辑状态】按钮,则会搜索整个
Json
中处于编辑状态
并符合关键词的数据。注意:如果有处于
插入状态
的数据,这时候会自动被删除。
上一个/下一个:当搜索完成后,点击【上一个】、【下一个】会自动跳转到相应的行。
查看概览:跳转到一个搜索结果概览控制器,显示了搜索结果的路径及value。
显示路径/搜索数量:在没有搜索条件(即:没有
搜索词
,且搜索
处于非选中状态)时,显示的是本控制器节点的路径。否则显示的是搜索结果数量。显示路径/错误信息:具有滚动、放大功能,最大放大倍数为1倍。
当搜索条件出现错误时,显示的是红色的错误信息。
当有搜索内容时,显示的是当前选中的搜索结果的节点路径。
删除功能
侧滑cell,出现删除功能(注意,因为侧滑功能比较多,所以在iphone5
上可能导致删除功能被遮挡)。
复制功能
复制功能分为两种:
- 如果侧滑
cell
对应的节点为Array
或Dictionary
则只能复制json
。 - 如果侧滑
cell
对应的节点为String
或Number
则可以复制json
与value
。
编辑功能
侧滑cell
,并点击编辑
按钮开启编辑功能(下面把被编辑的节点称为Model
,把Model
的父节点称为SuperModel
)。
SuperModel
类型对Model
的key
的影响:
SuperModel
点为Array
类型:Model
的key
必须为空。
SuperModel
为Dictionary
类型:Model
的key
必须有值。点击取消按钮:取消所有修改。
点击完成按钮:
选中
Number
按钮,转成Number
类型,输入的值必须为数字,否则会报错,并在错误位置进行显示。选中
String
按钮,转成String
类型,会有个默认值,默认值为""
。选中
json
按钮:
- 如果
Model
为Array
类型,则会把json
解析出来作为Model
的子节点数据。- 如果
Model
为Dictionary
类型,则会直接解析Json
,如果json
内包含一个对象则该对象作为Model
的数据,把对象的Key
作为Model
的key
。选中
Dictionary
按钮:
- 如果
Model
为Dictionary
类型,则不会产生任何效果;否则Model
清空子节点数据,并把Model
转成Dictionary
类型。选中
Array
按钮:如果
Model
为Array
类型,则不会产生任何效果;否则Model
清空子节点数据,并把Model
转成Array
类型。
插入功能
侧滑cell
,并点击插入
按钮开启编辑功能
注意:如果在插入
的节点
没有点击完成的情况下,对节点
的父节点
执行收起
操作,会自动删除刚刚插入的节点
。
注意:如果插入节点
的父节点
为Dictionary
类型,插入的节点
在父节点
中的顺序
不固定。
把被编辑的节点称为
Model
。把
Model
的父节点称为SuperModel
。把
Model
插入的子节点称为SubModel
。把
SuperModel
插入的子节点称为SuperSubModel
。
- 如果
Model
为Dictionary
则可以【插入子节点】或【插入父节点】。
- 【插入子节点】:
- 如果
Model
为关闭
状态,则自动展开Model
,并在Model
的字节点的第一行插入一个新的节点SubModel
,这时候,SubModel
处于被编辑状态
。- 注意:此时插入的
SubModel
在父节点Model
中 无序。- 【插入父节点】:在
Model
的后面插入为SuperSubModel
插入SuperSubModel
。- 如果
Model
为Array
类型,则可以【插入子节点】或【插入父节点】。
- 【插入子节点】:
- 如果
Model
为展开
状态,则自动压缩Model
,并在Model
的字节点的第一行插入一个新的节点SubModel
,这时候,SubModel
处于被编辑状态
。- 注意:此时插入的
SubModel
在父节点Model
有序。- 【插入父节点】:在
Model
的后面插入为SuperSubModel
插入SuperSubModel
。- 如果
Model
为String
或Number
类型,则可以【插入父节点】。在Model
的后面插入为SuperSubModel
插入SuperSubModel
实现思路
- 对
json
的解析 - 为了避免造成不必要的开销,对
json
解析的时机做了调整: - 当节点
A
被打开时,才会解析A
的子节点数据。 - 在解析节点
A
数据时,优先获取缓存的A
子节点数据。 - 在对
A
进行编辑
或插入
时,对A
的子节点数据进行更新。 - 对视图的展示
- 对于无限层级缩放的视图来说,我们有必要把数据展平。
- 数据中创建一个用于标记层级的变量。来做一个无限缩放层级的假象。
实现细节
对于节点Model的定义
Model
代表了一个节点,所以Model
的结构至关重要。
主要的属性:
- level:所处层级,在进行初始化时,根据父节点的
level
进行赋值。
@property (nonatomic,assign) NSInteger level;
- count:子节点的个数
@property (nonatomic,assign) NSInteger count;
- isOpen:是否为打开状态
@property (nonatomic,assign) BOOL isOpen;
- originData:所有子节点的原始数据(可能为nil、Array、Dictionary、Number、String)
@property (nonatomic,strong) id originData;
- key:如果originData为字典,则key就是originData的key,否则为nil
@property (nonatomic,strong) NSString *key;
- data:originData转化成的数据(可能为:nil、NSString、 NSArray、BaseJsonViewStepModel)
@property (nonatomic,strong) id data;
- originData:父节点(在父节点创建子节点时,进行的赋值)
@property (nonatomic,weak) BaseJsonViewStepModel *superPoint;
- type:当前节点的类型
typedef enum : NSUInteger {
BaseJsonViewStepModelType_Dictionary,
BaseJsonViewStepModelType_Array,
BaseJsonViewStepModelType_Number,
BaseJsonViewStepModelType_String,
} BaseJsonViewStepModelType;
@property (nonatomic,assign) BaseJsonViewStepModelType type;
- 所处的状态
typedef enum : NSUInteger {
BaseJsonViewStepCellStatus_Normal,
BaseJsonViewStepCellStatus_EditingSelf,
BaseJsonViewStepCellStatus_InsertItem,
} BaseJsonViewStepCellStatus;
@property (nonatomic,assign) BaseJsonViewStepCellStatus status;
对model的创建
+ (BaseJsonViewStepModel *) createStepModelWithOriginData: (id) data andKey: (NSString *)key
/**
创建 一个model
@param data 原始的子节点数据
@param key 创建出的model对应的key
@return model
*/
+ (BaseJsonViewStepModel *) createStepModelWithOriginData: (id) data andKey: (NSString *)key{
BaseJsonViewStepModel *model = [BaseJsonViewStepModel new];
model.originData = data;
model.key = key;
return model;
}
+ (BaseJsonViewStepModel *(^)(id)) createWithID
类方法,返回一个
block
,block
传入的是id类型的数据。数据可以是
BaseJsonViewStepModel
:直接返回这个data。不再创建NSString
:先转成字典,然后创建model
使用方法
BaseJsonViewStepModel.createWithId(data);
+ (BaseJsonViewStepModel *(^)(id)) createWithID {
return ^(id data) {
BaseJsonViewStepModel *model;
if ([data isKindOfClass:BaseJsonViewStepModel.class]) {
model = data;
}
if ([data isKindOfClass:NSString.class]) {
NSDictionary *dic = BaseJsonViewManager.convertToDicWithJson(data);
if (dic) {
model = BaseJsonViewManager.convertToStepModelWithDic(dic);
}
}
if (!model) {
model = [BaseJsonViewStepModel createStepModelWithOriginData:data andKey:@""];
}
return model;
};
}
搜索功能
搜索功能将搜索所有符合条件的model,并返回一个数组
isSearchEditing
筛选策略
- isSearchEditing:如果为true。
- 如果
key
为nil
,则搜索所有处于编辑状态的model。- 如果
key
有值
- 如果
isAccurateSearch
为true:搜索所有key
或value
的正在编辑状态的model
,等于key
。- 如果
isAccurateSearch
为true:搜索所有key
或value
包含key
的正在编辑状态的model
。
/**
搜索
@param key 搜索 关键字
@param isAccurateSearch 是否为精准搜索(如果选中精准搜索,搜索策略将从`containsString` 变成 `isEqualToString`。不管是否为精准搜索,都区分大小写)
@param isSearchEditing 是否搜索正在编辑状态的model
@return 搜索结果
*/
- (NSMutableArray <BaseJsonViewStepModel *>*) searchWithKey:(NSString *)key andIsAccurateSearch: (BOOL) isAccurateSearch andIsSearchEditing:(BOOL) isSearchEditing {
SBaseJsonViewStepSearchModelConfig config;
config.isSearchEditing = isSearchEditing;
config.isAccurateSearch = isAccurateSearch;
config.key = key;
config.model = self;
return BaseJsonViewStepSearchModel.getResultWithSearchConfig(config);
}
删除功能
从父节点移除本节点
此功能主要是找到originData中相同的元素,进行删除。
- (void) removeFromeSuper {
if ([self.superPoint.originData isKindOfClass:NSArray.class]) {
NSArray *array = self.superPoint.originData;
NSMutableArray *arrayM = [[NSMutableArray alloc]initWithArray:array];
[arrayM removeObject:self.originData];
self.superPoint.originData = arrayM;
}
if ([self.superPoint.originData isKindOfClass:NSDictionary.class]) {
NSDictionary *dic = self.superPoint.originData;
NSMutableDictionary *dicM = [[NSMutableDictionary alloc]initWithDictionary:dic];
NSString *key = self.key;
if (key.length > 0) {
dicM[self.key] = nil;
}
self.superPoint.originData = dicM;
}
[self.superPoint reloadDataWitOriginDataProperty];
}
插入节点
根据原始数据插入节点,并返回BaseJsonViewStepErrorModel
。
BaseJsonViewStepErrorModel
记录了插入时的错误信息
/**
插入一个节点
@param key 节点的key
@param originData 节点的原始子节点y数据
@param index 插入的位置
@return 插入报错的model
*/
- (BaseJsonViewStepErrorModel *) insertWithKey: (NSString *)key
andOriginData: (id) originData
andIndex:(NSInteger) index;
根据model插入节点,并返回BaseJsonViewStepErrorModel
。
BaseJsonViewStepErrorModel
记录了插入时的错误信息
/**
插入一个Model
@param model 准备插入的 节点 model
@param index 插入的位置
@return 错误信息
*/
- (BaseJsonViewStepErrorModel *) insertWithModel: (BaseJsonViewStepModel *) model
andIndex:(NSInteger) index;
最后
截图:
彩蛋:点击title
会复制当前Controller展示的json数据哦~
工具刚刚成型,许多地方需要修改,希望大家勇于提出bug,谢谢~