PYJsonViewManager 0.1.3

PYJsonViewManager 0.1.3

Maintained by lipengyue.



  • By
  • LiPengYue

PYJsonViewManager

CI Status Version License Platform

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.

demo地址

简介

描述

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. 搜索Editing:如果选中【搜Editing】按钮,则会搜索整个json中处在Editing状态并符合关键词搜索的数据。

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

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

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

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

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

  5. 当搜索条件报错时,展示的是红色的报错信息。

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

删除功能

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

复制功能

复制功能分为两种:

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

编辑功能

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

  1. SuperModel类型对Modelkey 的影响:

  2. SuperModel点为Array类型:Model的key必须为空。

  3. SuperModelDictionary类型:Model的key必须有值。

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

  5. 点击完成按钮:

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

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

  8. 选中json按钮:

    1. 如果ModelArray类型,则会把jons解析出来作为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 isEqualToString key的正在编辑状态的model
      2. 如果isAccurateSearch为true:搜索所有keyvalue containsString 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 谢谢~

demo地址