版本 0.1.3 的 PYJsonViewManager

PYJsonViewManager 0.1.3

lipengyue 维护。



  • LiPengYue

PYJsonViewManager

CI Status Version License Platform

示例

要运行示例项目,请首先将代码库克隆到本地,然后从 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结构展示:

  1. 一键压缩/展开:点击👀all展开全部,点击🦆…压缩全部(需要注意的是,如果进行了压缩,处在插入状态的cell将被删除)。
  2. 添加了层级的背景色、缩进等。默认最大展示6个层级,如果超过6个层级则跳转到新的页面进行展示。
  3. 对类型的区分:分为Dictionary Array String Number
  4. 支持展开与收起功能,若有子节点,则单击可以展开/收起。
  5. value的展示:一行cell的value默认最多展示两行。如果超过两行则压缩,并在底部展示。

搜索功能:

点击放大镜可以进入搜索界面

位置源码:在BaseJsonViewController->BaseJsonViewMainView->BaseJsonHeaderView->BaseJsonViewSearchView

  1. 搜索关键词:输入关键词,会自动进行搜索。

  2. 精确搜索:如果选中精确搜索,搜索策略将从containsString变成isEqualToString

注意:无论是否为精确搜索,都会区分大小写。

  1. 搜索编辑状态:如果选中【搜编辑状态】按钮,则会搜索整个Json中处于编辑状态并符合关键词的数据。

注意:如果有处于插入状态的数据,这时候会自动被删除。

  1. 上一个/下一个:当搜索完成后,点击【上一个】、【下一个】会自动跳转到相应的行。

  2. 查看概览:跳转到一个搜索结果概览控制器,显示了搜索结果的路径及value。

  3. 显示路径/搜索数量:在没有搜索条件(即:没有搜索词,且搜索处于非选中状态)时,显示的是本控制器节点的路径。否则显示的是搜索结果数量。

  4. 显示路径/错误信息:具有滚动、放大功能,最大放大倍数为1倍。

  5. 当搜索条件出现错误时,显示的是红色的错误信息。

  6. 当有搜索内容时,显示的是当前选中的搜索结果的节点路径。

删除功能

侧滑cell,出现删除功能(注意,因为侧滑功能比较多,所以在iphone5上可能导致删除功能被遮挡)。

复制功能

复制功能分为两种:

  1. 如果侧滑cell对应的节点为ArrayDictionary则只能复制 json
  2. 如果侧滑cell 对应的节点为StringNumber则可以复制jsonvalue

编辑功能

侧滑cell,并点击编辑按钮开启编辑功能(下面把被编辑的节点称为Model,把Model的父节点称为SuperModel)。

  1. SuperModel 类型对 Modelkey 的影响:

  2. SuperModel 点为 Array 类型:Modelkey 必须为空。

  3. SuperModelDictionary 类型:Modelkey 必须有值。

  4. 点击取消按钮:取消所有修改。

  5. 点击完成按钮:

  6. 选中 Number 按钮,转成 Number 类型,输入的值必须为数字,否则会报错,并在错误位置进行显示。

  7. 选中 String 按钮,转成 String 类型,会有个默认值,默认值为 ""

  8. 选中 json 按钮:

    1. 如果 ModelArray 类型,则会把 json 解析出来作为 Model 的子节点数据。
    2. 如果 ModelDictionary 类型,则会直接解析 Json,如果 json 内包含一个对象则该对象作为 Model 的数据,把对象的 Key 作为 Modelkey
  9. 选中 Dictionary 按钮:

    1. 如果 ModelDictionary 类型,则不会产生任何效果;否则 Model 清空子节点数据,并把 Model 转成 Dictionary 类型。
  10. 选中 Array 按钮:

    如果 ModelArray 类型,则不会产生任何效果;否则 Model 清空子节点数据,并把 Model 转成 Array 类型。

插入功能

侧滑cell,并点击插入按钮开启编辑功能

注意:如果在插入节点没有点击完成的情况下,对节点父节点执行收起操作,会自动删除刚刚插入的节点

注意:如果插入节点父节点Dictionary类型,插入的节点父节点中的顺序不固定。

把被编辑的节点称为 Model

Model 的父节点称为 SuperModel

Model 插入的子节点称为 SubModel

SuperModel 插入的子节点称为 SuperSubModel

  1. 如果 ModelDictionary 则可以【插入子节点】或【插入父节点】。
    1. 【插入子节点】:
      1. 如果 Model关闭状态,则自动展开 Model,并在 Model 的字节点的第一行插入一个新的节点 SubModel,这时候,SubModel 处于被 编辑状态
      2. 注意:此时插入的 SubModel 在父节点 Model无序
    2. 【插入父节点】:在 Model 的后面插入为 SuperSubModel 插入 SuperSubModel
  2. 如果 ModelArray 类型,则可以【插入子节点】或【插入父节点】。
    1. 【插入子节点】:
      1. 如果 Model展开状态,则自动压缩 Model,并在 Model 的字节点的第一行插入一个新的节点 SubModel,这时候,SubModel 处于被 编辑状态
      2. 注意:此时插入的SubModel在父节点Model有序
    2. 【插入父节点】:在 Model 的后面插入为 SuperSubModel 插入 SuperSubModel
  3. 如果ModelStringNumber类型,则可以【插入父节点】。在Model的后面插入为SuperSubModel插入SuperSubModel

实现思路

  1. json的解析
  2. 为了避免造成不必要的开销,对json解析的时机做了调整:
  3. 当节点A被打开时,才会解析A的子节点数据。
  4. 在解析节点A数据时,优先获取缓存的A子节点数据。
  5. 在对A进行编辑插入时,对A的子节点数据进行更新。
  6. 对视图的展示
  7. 对于无限层级缩放的视图来说,我们有必要把数据展平。
  8. 数据中创建一个用于标记层级的变量。来做一个无限缩放层级的假象。

实现细节

对于节点Model的定义

Model代表了一个节点,所以Model的结构至关重要。

主要的属性:
  1. level:所处层级,在进行初始化时,根据父节点的level进行赋值。
@property (nonatomic,assign) NSInteger level;
  1. count:子节点的个数
@property (nonatomic,assign) NSInteger count;
  1. isOpen:是否为打开状态
@property (nonatomic,assign) BOOL isOpen;
  1. originData:所有子节点的原始数据(可能为nil、Array、Dictionary、Number、String)
@property (nonatomic,strong) id originData;
  1. key:如果originData为字典,则key就是originData的key,否则为nil
@property (nonatomic,strong) NSString *key;
  1. data:originData转化成的数据(可能为:nil、NSString、 NSArray、BaseJsonViewStepModel)
@property (nonatomic,strong) id data;
  1. originData:父节点(在父节点创建子节点时,进行的赋值)
@property (nonatomic,weak) BaseJsonViewStepModel *superPoint;
  1. type:当前节点的类型
typedef enum : NSUInteger {
BaseJsonViewStepModelType_Dictionary,
BaseJsonViewStepModelType_Array,
BaseJsonViewStepModelType_Number,
BaseJsonViewStepModelType_String,
} BaseJsonViewStepModelType;

@property (nonatomic,assign) BaseJsonViewStepModelType type;
  1. 所处的状态
typedef enum : NSUInteger {
BaseJsonViewStepCellStatus_Normal,
BaseJsonViewStepCellStatus_EditingSelf,
BaseJsonViewStepCellStatus_InsertItem,
} BaseJsonViewStepCellStatus;

@property (nonatomic,assign) BaseJsonViewStepCellStatus status;
对model的创建
  1. + (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;
}    
  1. + (BaseJsonViewStepModel *(^)(id)) createWithID

类方法,返回一个blockblock 传入的是id类型的数据。数据可以是

  1. BaseJsonViewStepModel:直接返回这个data。不再创建
  2. 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筛选策略

  1. isSearchEditing:如果为true。
    1. 如果keynil,则搜索所有处于编辑状态的model。
    2. 如果key有值
      1. 如果isAccurateSearch为true:搜索所有keyvalue的正在编辑状态的model,等于key
      2. 如果isAccurateSearch为true:搜索所有keyvalue包含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,谢谢~

演示地址