树形结构
- 层次嵌套
- 外层和内层具有相似的结构
- 可以递归的表示
简易的二叉树
Node
@interface Node : NSObject
@property (nonatomic, strong) NSString *nodeName;
@property (nonatomic, strong) Node *leftNode;
@property (nonatomic, strong) Node *rightNode;
+ (instancetype)nodeWithName:(NSString *)nodeName;
@implementation Node
+ (instancetype)nodeWithName:(NSString *)nodeName {
//这里用self,因为它可能会被子类继承
Node *node = [[[self class] alloc] init];
node.nodeName = nodeName;
return node;
}
@end
ViewController
@interface ViewController ()
@property (nonatomic, strong) Node *rootNode;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.rootNode = [Node nodeWithName:@"A"];
// 插入节点
[self insertNodeTree:self.rootNode node:[Node nodeWithName:@"B"]];
[self insertNodeTree:self.rootNode node:[Node nodeWithName:@"C"]];
[self insertNodeTree:self.rootNode node:[Node nodeWithName:@"D"]];
[self insertNodeTree:self.rootNode node:[Node nodeWithName:@"E"]];
[self insertNodeTree:self.rootNode node:[Node nodeWithName:@"F"]];
// 遍历二叉树
[self treeInfomationWithNode:self.rootNode];
}
//往根节点上插入节点
- (void)insertNodeTree:(Node *)tree node:(Node *)node {
if (tree.leftNode == nil) {
tree.leftNode = node;
return;
}
if (tree.rightNode == nil) {
tree.rightNode = node;
return;
}
[self insertNodeTree:tree.leftNode node:node];
}
// 遍历二叉树
- (void)treeInfomationWithNode:(Node *)node {
if (node.leftNode) {
[self treeInfomationWithNode:node.leftNode];
}
NSLog(@"%@", node.nodeName);
if (node.rightNode) {
[self treeInfomationWithNode:node.rightNode];
}
@end
组合模式
- 组合模式,将对象组合成树形结构以表示“部分-整体”的层次结构,组合模式使得用户对单个对象和组合对象的使用具有一致性。
- 掌握组合模式的重点是要理解清楚 “部分/整体” 还有 ”单个对象“ 与 “组合对象” 的含义。
Node
@interface Node : NSObject
@property (nonatomic, strong) NSString *nodeName;
//便利构造器
+ (instancetype)nodeWithNodeName:(NSString *)nodeName;
//子节点集合
@property (nonatomic, strong, readonly) NSMutableArray <Node *> *childNodes;
//添加子节点
- (void)addNode:(Node *)node;
//删除子节点
- (void)removeNode:(Node *)node;
//获取子节点
- (Node *)nodeAtIndex:(NSInteger)index;
//打印Node
- (void)operation;
@end
//------------------------------------------------------------------------
@interface Node ()
@property (nonatomic, strong) NSMutableArray <Node *> *childNodes;
@end
@implementation Node
- (instancetype)init {
self = [super init];
if (self) {
self.childNodes = [NSMutableArray array];
}
return self;
}
+ (instancetype)nodeWithNodeName:(NSString *)nodeName {
Node *node = [[[self class] alloc] init];
node.nodeName = nodeName;
return node;
}
- (void)addNode:(Node *)node {
[self.childNodes addObject:node];
}
- (void)removeNode:(Node *)node {
[self.childNodes removeObject:node];
}
- (Node *)nodeAtIndex:(NSInteger)index {
if (index >= self.childNodes.count) {
return nil;
} else {
return self.childNodes[index];
}
}
- (void)operation {
NSLog(@"nodeName --> %@", self.nodeName);
}
- (NSString *)description {
return [NSString stringWithFormat:@"[Node] - %@", self.nodeName];
}
@end
ViewController
@interface ViewController ()
@property (nonatomic, strong) Node *rootNode;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// 创建根节点
self.rootNode = [Node nodeWithNodeName:@"A"];
// 创建第一级子节点(A -> B,C,D)
[self.rootNode addNode:[Node nodeWithNodeName:@"B"]];
Node *c = [Node nodeWithNodeName:@"C"];
[self.rootNode addNode:c];
[self.rootNode addNode:[Node nodeWithNodeName:@"D"]];
// 创建第二级子节点(C -> E,F)
[c addNode:[Node nodeWithNodeName:@"E"]];
[c addNode:[Node nodeWithNodeName:@"F"]];
NSLog(@"%@", self.rootNode.childNodes);
NSLog(@"%@", c.childNodes);
}
编写文件夹系统
File
typedef enum : NSUInteger {
kFile, // 文件
kFolder, // 文件夹
} EFile;
@interface File : NSObject
//文件夹或者文件的名字,根据EFile类别来区分
@property (nonatomic, strong) NSString *name;
//文件类型
@property (nonatomic) EFile fileType;
//子文件集合
@property (nonatomic, strong, readonly) NSMutableArray <File *> *childFiles;
//添加文件
- (void)addFile:(File *)file;
//便利构造器
+ (instancetype)fileWithFileType:(EFile)fileType fileName:(NSString *)name;
@end
-------------------------------------------------------------
@interface File ()
@property (nonatomic, strong) NSMutableArray <File *> *childFiles;
@end
@implementation File
- (instancetype)init {
self = [super init];
if (self) {
self.childFiles = [NSMutableArray array];
}
return self;
}
- (void)addFile:(File *)file {
NSParameterAssert(file);
[self.childFiles addObject:file];
}
+ (instancetype)fileWithFileType:(EFile)fileType fileName:(NSString *)name {
File *file = [[[self class] alloc] init];
file.fileType = fileType;
file.name = name;
return file;
}
@end
FileCell
@interface FileCell : UITableViewCell
@property (nonatomic, weak) id data;
@property (nonatomic, weak) NSIndexPath *indexPath;
@property (nonatomic, weak) UITableView *tableView;
@property (nonatomic, weak) UIViewController *controller;
- (void)loadContent;
@end
---------------------------------------------------------------------
@interface FileCell ()
@property (nonatomic, strong) UIImageView *fileImageView;
@property (nonatomic, strong) UIImageView *folderImageView;
@property (nonatomic, strong) UILabel *iconNameLabel;
@property (nonatomic, strong) UIButton *button;
@property (nonatomic, strong) UILabel *nameLabel;
@end
@implementation FileCell
- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {
if (self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]) {
self.selectionStyle = UITableViewCellSelectionStyleNone;
[self buildView];
}
return self;
}
- (void)buildView {
UIView *line = [[UIView alloc] initWithFrame:CGRectMake(0, 79.5f, 500, 0.5f)];
line.backgroundColor = [[UIColor grayColor] colorWithAlphaComponent:0.25f];
[self addSubview:line];
self.fileImageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"File"]];
self.folderImageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"Folder"]];
self.fileImageView.center = CGPointMake(40, 50);
self.folderImageView.center = CGPointMake(40, 50);
[self addSubview:self.folderImageView];
[self addSubview:self.fileImageView];
self.iconNameLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 13, 80, 20)];
self.iconNameLabel.font = [UIFont fontWithName:@"AppleSDGothicNeo-Light" size:12.f];
self.iconNameLabel.textAlignment = NSTextAlignmentCenter;
[self addSubview:self.iconNameLabel];
self.nameLabel = [[UILabel alloc] initWithFrame:CGRectMake(80, 10, 200, 60)];
self.nameLabel.font = [UIFont fontWithName:@"Avenir-Book" size:12.f];
[self addSubview:self.nameLabel];
self.button = [[UIButton alloc] initWithFrame:CGRectMake(0, 0, 500, 80)];
[self.button addTarget:self
action:@selector(buttonEvent)
forControlEvents:UIControlEventTouchUpInside];
[self addSubview:self.button];
}
- (void)loadContent {
File *file = self.data;
self.nameLabel.text = file.name;
if (file.fileType == kFolder) {
[self changeToFolderState];
} else if (file.fileType == kFile) {
[self changeToFileState];
}
}
//切换到文件夹状态
- (void)changeToFolderState {
self.fileImageView.hidden = YES;
self.folderImageView.hidden = NO;
self.iconNameLabel.textColor = [UIColor blackColor];
self.nameLabel.textColor = [UIColor blackColor];
self.iconNameLabel.text = @"Folder";
}
//切换到文件状态
- (void)changeToFileState {
self.fileImageView.hidden = NO;
self.folderImageView.hidden = YES;
self.iconNameLabel.textColor = [UIColor grayColor];
self.nameLabel.textColor = [UIColor grayColor];
self.iconNameLabel.text = @"File";
}
- (void)buttonEvent {
File *file = self.data;
if (file.fileType == kFolder) {
FileViewController *fvc = [[FileViewController alloc] init];
fvc.rootFile = file;
[self.controller.navigationController pushViewController:fvc
animated:YES];
}
}
@end
FileViewController
@interface FileViewController : UIViewController
@property (nonatomic, strong) File *rootFile;
@end
-----------------------------------------------------------------
@interface FileViewController () <UITableViewDelegate, UITableViewDataSource>
@property (nonatomic, strong) UITableView *tableView;
@end
@implementation FileViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.title = self.rootFile.name;
[self initTableView];
}
#pragma mark - tableView相关
- (void)initTableView {
self.tableView = [[UITableView alloc] initWithFrame:self.view.bounds style:UITableViewStylePlain];
self.tableView.delegate = self;
self.tableView.dataSource = self;
self.tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
[self.tableView registerClass:[FileCell class] forCellReuseIdentifier:@"fileCell"];
[self.view addSubview:self.tableView];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return self.rootFile.childFiles.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
FileCell *cell = [tableView dequeueReusableCellWithIdentifier:@"fileCell"];
cell.indexPath = indexPath;
cell.tableView = tableView;
cell.controller = self;
// 传入节点File
cell.data = self.rootFile.childFiles[indexPath.row];
[cell loadContent];
return cell;
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
return 80.f;
}
@end
ViewController
@interface ViewController ()<UITableViewDelegate, UITableViewDataSource>
@property (nonatomic, strong) UITableView *tableView;
@property (nonatomic, strong) File *root;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
self.title = @"Root";
// 创建根节点
self.root = [File fileWithFileType:kFolder fileName:@"root"];
// 创建第一级文件
File *folder_A_1 = [File fileWithFileType:kFolder fileName:@"Folder-A-1"];
File *file_A_2 = [File fileWithFileType:kFile fileName:@"File-A-2"];
File *file_A_3 = [File fileWithFileType:kFile fileName:@"File-A-3"];
File *file_A_4 = [File fileWithFileType:kFile fileName:@"File-A-4"];
// 创建第二级文件
File *folder_B_1 = [File fileWithFileType:kFolder fileName:@"Folder-B-1"];
File *file_B_2 = [File fileWithFileType:kFile fileName:@"File-B-2"];
File *file_B_3 = [File fileWithFileType:kFile fileName:@"File-B-3"];
File *folder_B_2 = [File fileWithFileType:kFolder fileName:@"Folder-B-2"];
// 创建第三级文件
File *folder_C_1 = [File fileWithFileType:kFolder fileName:@"Folder-C-1"];
File *file_C_1 = [File fileWithFileType:kFile fileName:@"File-C-1"];
File *file_C_2 = [File fileWithFileType:kFile fileName:@"File-C-2"];
[self.root addFile:folder_A_1];
[self.root addFile:file_A_2];
[self.root addFile:file_A_3];
[self.root addFile:file_A_4];
[folder_A_1 addFile:folder_B_1];
[folder_A_1 addFile:file_B_2];
[folder_A_1 addFile:file_B_3];
[folder_A_1 addFile:folder_B_2];
[folder_B_1 addFile:folder_C_1];
[folder_B_1 addFile:file_C_1];
[folder_B_2 addFile:file_C_2];
[self initTableView];
}
#pragma mark - tableView相关
- (void)initTableView {
self.tableView = [[UITableView alloc] initWithFrame:self.view.bounds style:UITableViewStylePlain];
self.tableView.delegate = self;
self.tableView.dataSource = self;
self.tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
[self.tableView registerClass:[FileCell class] forCellReuseIdentifier:@"fileCell"];
[self.view addSubview:self.tableView];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return self.root.childFiles.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
FileCell *cell = [tableView dequeueReusableCellWithIdentifier:@"fileCell"];
cell.indexPath = indexPath;
cell.tableView = tableView;
cell.controller = self;
// 传入节点File
cell.data = self.root.childFiles[indexPath.row];
[cell loadContent];
return cell;
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
return 80.f;
}
@end
Node类里含有Node的属性
Node.h
@property (nonatomic, strong) Node *leftNode;
Node.h
@property (nonatomic, strong) NSMutableArray <Node *> *childNodes;
便利构造器里调用alloc init方法
+ (instancetype)nodeWithNodeName:(NSString *)nodeName {
//使用self class以便子类继承
Node *node = [[[self class] alloc] init];
node.nodeName = nodeName;
return node;
}
Override init method
- (instancetype)init {
self = [super init];
if (self) {
self.childNodes = [NSMutableArray array];
}
return self;
}
调用description显示对象的打印结果
- (NSString *)description {
return [NSString stringWithFormat:@"[Node] - %@", self.nodeName];
}
枚举类型的属性和参数
typedef enum : NSUInteger {
kFile, // 文件
kFolder, // 文件夹
} EFile;
@property (nonatomic) EFile fileType;
+ (instancetype)fileWithFileType:(EFile)fileType fileName:(NSString *)name;
表视图间隔灰线
UIView *line = [[UIView alloc] initWithFrame:CGRectMake(0, 79.5f, 500, 0.5f)];
line.backgroundColor = [[UIColor grayColor] colorWithAlphaComponent:0.25f];
[self addSubview:line];
以中心定位某视图
self.fileImageView.center = CGPointMake(40, 50);
self.folderImageView.center = CGPointMake(40, 50);
视图导航栏的标签设定
- (void)viewDidLoad {
[super viewDidLoad];
self.title = self.rootFile.name;
[self initTableView];
}
代码创建tableView
- (void)initTableView {
self.tableView = [[UITableView alloc] initWithFrame:self.view.bounds style:UITableViewStylePlain];
self.tableView.delegate = self;
self.tableView.dataSource = self;
self.tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
[self.tableView registerClass:[FileCell class] forCellReuseIdentifier:@"fileCell"];
[self.view addSubview:self.tableView];
}
代码创建tableViewCell
FileCell
- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {
if (self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]) {
self.selectionStyle = UITableViewCellSelectionStyleNone;
[self buildView];
}
return self;
}
ViewController
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
FileCell *cell = [tableView dequeueReusableCellWithIdentifier:@"fileCell"];
cell.indexPath = indexPath;
cell.tableView = tableView;
cell.controller = self;
// 传入节点File
cell.data = self.root.childFiles[indexPath.row];
[cell loadContent];
return cell;
}
[Self class]
File *file = [[[self class] alloc] init];