- iOS : 根据 JSON 创建一棵树
- iOS : Make a tree based on a JSON
最近几天,我遇到了一个我无法解决的问题。
确实,我在 JSON 中有一些数据。我解析了这个JSON,一切正常。
这是 JSON 的结构:
{
"obs" : [
{
"CategoryId": 1,
"Title": "Category 1",
"Description": "Description 1",
"ParentCategoryId": null
},
{
"CategoryId": 2,
"Title": "Category 2",
"Description": "Description 2",
"ParentCategoryId": null
},
{
"CategoryId": 3,
"Title": "Category 3",
"Description": null,
"ParentCategoryId": null
},
{
"CategoryId": 4,
"Title": "Category 1.1",
"Description": "Description 1.1",
"ParentCategoryId": 1
},
{
"CategoryId": 5,
"Title": "Category 1.2",
"Description": "Description 1.2",
"ParentCategoryId": 1
},
{
"CategoryId": 6,
"Title": "Category 1.1.1",
"Description": null,
"ParentCategoryId": 4
},
{
"CategoryId": 7,
"Title": "Category 1.1.2",
"Description": null,
"ParentCategoryId": 4
},
{
"CategoryId": 8,
"Title": "Category 1.1.1.1",
"Description": null,
"ParentCategoryId": 6
},
{
"CategoryId": 9,
"Title": "Category 1.3",
"Description": "Category 1.3",
"ParentCategoryId": 1
}
]
}
这些对象的模型 (.h) 我正在使用图书馆 JSON模型:
@class CategoryModel;
@protocol CategoryModel @end
@interface CategoriesModel : JSONModel
@property (nonatomic, strong) NSArray<CategoryModel> * obs;
@end
@interface CategoryModel : JSONModel
@property (nonatomic, strong) NSNumber * CategoryId;
@property (nonatomic, strong) NSString * Title;
@property (nonatomic, strong) NSString<Optional> * Description;
@property (nonatomic, strong) NSNumber<Optional> * ParentCategoryId;
@end
然后,在视图控制器中,在获取 JSON 的数据并解析它之后,我想制作一个 NSDictionary、NSArray 或类似树的东西,以将这些类别显示在一个以 UITableView 为例。
我的问题是:我无法找到 "sort" 这些数据的解决方案并用它制作一棵树。
这里是我现在的方法:
- (void)parseJSON
{
NSError * error;
NSString *filePath = [[NSBundle mainBundle] pathForResource:@"list" ofType:@"json"];
NSString *jsonString = [NSString stringWithContentsOfFile:filePath encoding:NSUTF8StringEncoding error:&error];
self.myJSON = [[CategoriesModel alloc] initWithString:jsonString error:&error];
for(CategoryModel * obs in self.myJSON.obs)
{
if(obs.ParentCategoryId)
{
CategoryModel * parent = [self searchParentObjectForChild:obs];
NSLog(@"Parent of %@(ID:%ld) : %@(ID:%ld)", obs.Title, [obs.CategoryId integerValue], parent.Title, [parent.CategoryId integerValue]);
}
else
{
NSLog(@"%@(ID: %@) doesn't have a parent",obs.Title, obs.CategoryId);
}
}
}
- (CategoryModel *)searchParentObjectForChild:(CategoryModel *)child
{
for (CategoryModel * obs in self.myJSON.obs)
{
if(obs.CategoryId == child.ParentCategoryId)
{
return obs;
}
}
return nil;
}
注意:如果可能,不要改变JSON的结构。
如果有人知道我该如何实现,请告诉我。
也欢迎任何建议!
谢谢。
我假设您有一个 class 的数组,并想从中构建一个新数组:)
@interface CategoryModel
@property (nonatomic, strong) NSNumber * CategoryId;
@property (nonatomic, strong) NSString * Title;
@property (nonatomic, strong) NSString * Description;
@property (nonatomic, strong) NSNumber * ParentCategoryId;
@end
首先,让我们向每个类别添加另一个 属性,这将使您在应用程序逻辑中使用树时更轻松。
@property (nonatomic, strong) NSMutableArray* subCategories;
现在你可能想写这样的东西(请注意,对于大量类别这可能需要很长时间,所以我更喜欢你找到一个已知的算法来构建你的树(可能是 AVL 树或其他东西)) 但对于数百个类别,一切都应该没问题。
- (void)findCategoryChildren:(CategoryModel*)category fromArray:(NSMutableArray*)originalCopy currentIndex:(int*)i {
for (int j = 0; j < originalCopy.count; j++) {
CategoryModel* childCategory = originalCopy[j];
if ([childCategory.ParentCategoryId intValue] == [category.CategoryId intValue]) {
if (category.subCategories == nil) {
category.subCategories = [[NSMutableArray alloc] init];
}
[category.subCategories addObject:childCategory];
[originalCopy removeObjectAtIndex:j];
j--;
i--;
// Now find the childs of this child category
[self findCategoryChildren:childCategory fromArray:originalCopy currentIndex:i];
}
}
}
- (NSArray*)sort:(NSArray*)original {
// This is the final array (the tree)
NSMutableArray* result = [[NSMutableArray alloc] init];
// This is a copy of the input to minimize the time of the latter iterations
NSMutableArray* originalCopy = [[NSMutableArray alloc] initWithArray:original];
for (int i = 0; i < originalCopy.count; i++) {
CategoryModel* category = originalCopy[i];
// This is a root category
if (category.ParentCategoryId == nil) {
[result addObject:category];
[originalCopy removeObjectAtIndex:i];
i--;
// Now try to find its children
[self findCategoryChildren:category fromArray:originalCopy currentIndex:&i];
}
}
return result;
}
最近几天,我遇到了一个我无法解决的问题。 确实,我在 JSON 中有一些数据。我解析了这个JSON,一切正常。
这是 JSON 的结构:
{
"obs" : [
{
"CategoryId": 1,
"Title": "Category 1",
"Description": "Description 1",
"ParentCategoryId": null
},
{
"CategoryId": 2,
"Title": "Category 2",
"Description": "Description 2",
"ParentCategoryId": null
},
{
"CategoryId": 3,
"Title": "Category 3",
"Description": null,
"ParentCategoryId": null
},
{
"CategoryId": 4,
"Title": "Category 1.1",
"Description": "Description 1.1",
"ParentCategoryId": 1
},
{
"CategoryId": 5,
"Title": "Category 1.2",
"Description": "Description 1.2",
"ParentCategoryId": 1
},
{
"CategoryId": 6,
"Title": "Category 1.1.1",
"Description": null,
"ParentCategoryId": 4
},
{
"CategoryId": 7,
"Title": "Category 1.1.2",
"Description": null,
"ParentCategoryId": 4
},
{
"CategoryId": 8,
"Title": "Category 1.1.1.1",
"Description": null,
"ParentCategoryId": 6
},
{
"CategoryId": 9,
"Title": "Category 1.3",
"Description": "Category 1.3",
"ParentCategoryId": 1
}
]
}
这些对象的模型 (.h) 我正在使用图书馆 JSON模型:
@class CategoryModel;
@protocol CategoryModel @end
@interface CategoriesModel : JSONModel
@property (nonatomic, strong) NSArray<CategoryModel> * obs;
@end
@interface CategoryModel : JSONModel
@property (nonatomic, strong) NSNumber * CategoryId;
@property (nonatomic, strong) NSString * Title;
@property (nonatomic, strong) NSString<Optional> * Description;
@property (nonatomic, strong) NSNumber<Optional> * ParentCategoryId;
@end
然后,在视图控制器中,在获取 JSON 的数据并解析它之后,我想制作一个 NSDictionary、NSArray 或类似树的东西,以将这些类别显示在一个以 UITableView 为例。
我的问题是:我无法找到 "sort" 这些数据的解决方案并用它制作一棵树。
这里是我现在的方法:
- (void)parseJSON
{
NSError * error;
NSString *filePath = [[NSBundle mainBundle] pathForResource:@"list" ofType:@"json"];
NSString *jsonString = [NSString stringWithContentsOfFile:filePath encoding:NSUTF8StringEncoding error:&error];
self.myJSON = [[CategoriesModel alloc] initWithString:jsonString error:&error];
for(CategoryModel * obs in self.myJSON.obs)
{
if(obs.ParentCategoryId)
{
CategoryModel * parent = [self searchParentObjectForChild:obs];
NSLog(@"Parent of %@(ID:%ld) : %@(ID:%ld)", obs.Title, [obs.CategoryId integerValue], parent.Title, [parent.CategoryId integerValue]);
}
else
{
NSLog(@"%@(ID: %@) doesn't have a parent",obs.Title, obs.CategoryId);
}
}
}
- (CategoryModel *)searchParentObjectForChild:(CategoryModel *)child
{
for (CategoryModel * obs in self.myJSON.obs)
{
if(obs.CategoryId == child.ParentCategoryId)
{
return obs;
}
}
return nil;
}
注意:如果可能,不要改变JSON的结构。
如果有人知道我该如何实现,请告诉我。 也欢迎任何建议! 谢谢。
我假设您有一个 class 的数组,并想从中构建一个新数组:)
@interface CategoryModel
@property (nonatomic, strong) NSNumber * CategoryId;
@property (nonatomic, strong) NSString * Title;
@property (nonatomic, strong) NSString * Description;
@property (nonatomic, strong) NSNumber * ParentCategoryId;
@end
首先,让我们向每个类别添加另一个 属性,这将使您在应用程序逻辑中使用树时更轻松。
@property (nonatomic, strong) NSMutableArray* subCategories;
现在你可能想写这样的东西(请注意,对于大量类别这可能需要很长时间,所以我更喜欢你找到一个已知的算法来构建你的树(可能是 AVL 树或其他东西)) 但对于数百个类别,一切都应该没问题。
- (void)findCategoryChildren:(CategoryModel*)category fromArray:(NSMutableArray*)originalCopy currentIndex:(int*)i {
for (int j = 0; j < originalCopy.count; j++) {
CategoryModel* childCategory = originalCopy[j];
if ([childCategory.ParentCategoryId intValue] == [category.CategoryId intValue]) {
if (category.subCategories == nil) {
category.subCategories = [[NSMutableArray alloc] init];
}
[category.subCategories addObject:childCategory];
[originalCopy removeObjectAtIndex:j];
j--;
i--;
// Now find the childs of this child category
[self findCategoryChildren:childCategory fromArray:originalCopy currentIndex:i];
}
}
}
- (NSArray*)sort:(NSArray*)original {
// This is the final array (the tree)
NSMutableArray* result = [[NSMutableArray alloc] init];
// This is a copy of the input to minimize the time of the latter iterations
NSMutableArray* originalCopy = [[NSMutableArray alloc] initWithArray:original];
for (int i = 0; i < originalCopy.count; i++) {
CategoryModel* category = originalCopy[i];
// This is a root category
if (category.ParentCategoryId == nil) {
[result addObject:category];
[originalCopy removeObjectAtIndex:i];
i--;
// Now try to find its children
[self findCategoryChildren:category fromArray:originalCopy currentIndex:&i];
}
}
return result;
}