PYJsonViewManager
Example
To run the example project, clone the repo, and run pod install from the Example directory first.
Requirements
Installation
PYJsonViewManager is available through CocoaPods. To install it, simply add the following line to your Podfile:
pod 'PYJsonViewManager'Author
LiPengYue, [email protected]
License
PYJsonViewManager is available under the MIT license. See the LICENSE file for more info.
简介
描述
BaseJsonViewController是一个用OC编写的提供了搜索、插入、编辑、查看路径、复制json/value 等功能的Json可视化编辑工具。
由于网络数据请求下来后,
APP端对json原数据的展示并不明朗。 修改网络数据只能通过Charles等抓包工具实现,受到的限制太多,所以诞生了在APP端直接对json进行查看、修改的Json视图工具:BaseJsonViewController。后续会对
BaseJsonViewController进行持续的更新优化,欢迎使用。
主要功能
json结构展示:
- 一键压缩/展开 : 点击
👀all展开全部,点击🦆…压缩全部(需要注意的是,如果进行了压缩,处在插入状态的cell,将被删除)。 - 添加了层级的背景色、缩进等。默认最大展示6个层级,如果超过6个层级则跳转到新的页面,进行展示。
- 对类型的区分:分为
DictionaryArrayStringNumber。 - 支持展开与收起功能,如果有子节点,则单击可以展开\收起。
- value的展示:一行cell 的 value默认最多展示两行。如果超过两行则压缩,并在底部展示。
搜索功能:
点击放大镜可以进入搜索页面
在源码中的位置:BaseJsonViewController->BaseJsonViewMainView->BaseJsonHeaderView->BaseJsonViewSearchView
搜索关键词:输入关键词,并且会自动进行搜索。
精准搜索:如果选中精准搜索,搜索策略将从
containsString变成isEqualToString。注意:不管是否为精准搜索,都区分大小写。
- 搜索Editing:如果选中【搜Editing】按钮,则会搜索整个
json中处在Editing状态并符合关键词搜索的数据。注意:如果有处在
插入状态的数据,这时候会自动被删除。
上一个\下一个:当搜索完成后,点击【上一个】、【下一个】自动跳转到相应的行。
查看总览:跳转到一个搜索结果总览控制器,显示了搜索结果的路径及`value
展示路径/搜索数量:当没有搜索条件(即:没有
搜索词、且搜Editing处于非选中状态)时,显示的是本控制器节点的路径。否则显示的是搜索结果数量。展示路径/报错信息:具有滚动、放大功能,最大放大倍数为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按钮,转成Numbser类型,输入的值必须为数字,否则会报错,并在报错位置进行显示。选中
String按钮,转成String类型,会有个默认值,默认值为""。选中
json按钮:
- 如果
Model为Array类型,则会把jons解析出来作为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或valueisEqualToStringkey的正在编辑状态的model- 如果
isAccurateSearch为true:搜索所有key或valuecontainsStringkey的正在编辑状态的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 谢谢~