最近项目活比较少,没事写了一个框架,也是对以前开发的总结。那我写这个是干嘛用呢? 我把app中页面的跳转用xml描述,程序会自动解析,各页面对象的创建也由框架管理创建,这样由老大搞好流程,下面小弟就只关心各自负责的页面功能开发就行。低耦合,高内聚。 先看下图。其中frame是核心部分。另外借用了第三方LCNavigationController和GDataXML。前者是页面跳转,后者是xml解析。如何使用自行百度。
上图中的datainfo.xml文件就是页面跳转的逻辑描述。
是这个样子:
<?xml version="1.0" encoding = "UTF-8"?>
<info>
<class>
<classname>ViewController</classname>
<nextclass>
<nextclassname>
<id>Test2</id>
<name>Test2Controller</name>
</nextclassname>
</nextclass>
</class>
<class>
<classname>Test2Controller</classname>
<nextclass>
<nextclassname>
<id>Test3</id>
<name>Test3Controller</name>
</nextclassname>
<nextclassname>
<id>Test4</id>
<name>Test4Controller</name>
</nextclassname>
</nextclass>
<prevclass>
<prevclassname>
<id>View</id>
<name>ViewController</name>
</prevclassname>
</prevclass>
</class>
<class>
<classname>Test3Controller</classname>
<prevclass>
<prevclassname>
<id>Test2</id>
<name>Test2Controller</name>
</prevclassname>
</prevclass>
</class>
<class>
<classname>Test4Controller</classname>
<prevclass>
<prevclassname>
<id>Test2</id>
<name>Test2Controller</name>
</prevclassname>
</prevclass>
</class>
</info>
标签<class></class>为一组。<classname>是当前的页面,<nextclassname>是跳转下一个页面,<prevclassname>是返回上一个页面。结构还是很简单的。
Manager是单例类(单例怎么写,不用我介绍了)。主要是解析xml文件和初始化。看截图:
-(void) loadorganizationformdatainfo{
NSString *filePath=[[NSBundle mainBundle] pathForResource:@"datainfo" ofType:@"xml"];
NSData *xmlData = [[NSData alloc] initWithContentsOfFile:filePath];
classtreedic = [[NSMutableDictionary alloc] init];
//使用NSData对象初始化
GDataXMLDocument *doc = [[GDataXMLDocument alloc] initWithData:xmlData options:0 error:nil];
NSString *Name;
//获取根节点(Users)
GDataXMLElement *rootElement = [doc rootElement];
NSArray *anyTypes=[rootElement elementsForName:@"class"];
for (GDataXMLElement *anyType in anyTypes ) {
//主体部分,class名字。
GDataXMLElement *NameID=[[anyType elementsForName:@"classname"] objectAtIndex:0];
Name = [NameID stringValue];
nodeclass = [[Classmodel alloc] init];
nodeclass.prevclassnamedict = [[NSMutableDictionary alloc] init];
nodeclass.nextclassnamedict = [[NSMutableDictionary alloc] init];
[nodeclass setClassname:Name];
NSLog(@"name is %@",Name);
//跳转下一个class设定
GDataXMLElement *enextclass = [[anyType elementsForName:@"nextclass"] objectAtIndex:0] ;
NSArray *types = [enextclass elementsForName:@"nextclassname"];
for (GDataXMLElement *eType in types) {
//GDataXMLElement *nextclassname=[[eType elementsForName:@"nextclassname"] objectAtIndex:0];
NSString *str_id = [[[eType elementsForName:@"id"] objectAtIndex:0] stringValue];
NSString *str_nextclassname = [[[eType elementsForName:@"name"] objectAtIndex:0] stringValue];
[nodeclass.nextclassnamedict setValue:str_nextclassname forKey:str_id];
NSLog(@"nextclassID is %@",str_id);
NSLog(@"nextclassname is %@",str_nextclassname);
}
//返回上一个class设定
GDataXMLElement *eprevclass = [[anyType elementsForName:@"prevclass"] objectAtIndex:0] ;
NSArray *ptypes = [eprevclass elementsForName:@"prevclassname"];
for (GDataXMLElement *pType in ptypes) {
//GDataXMLElement *nextclassname=[[eType elementsForName:@"nextclassname"] objectAtIndex:0];
NSString *str_id = [[[pType elementsForName:@"id"] objectAtIndex:0] stringValue];
NSString *str_prevclassname = [[[pType elementsForName:@"name"] objectAtIndex:0] stringValue];
[nodeclass.prevclassnamedict setValue:str_prevclassname forKey:str_id];
NSLog(@"prevclassID is %@",str_id);
NSLog(@"prevclassname is %@",str_prevclassname);
}
[classtreedic setValue:nodeclass forKey:Name];
}
NSLog(@"%@",classtreedic);
}
-(void) initforclassname:(UIViewController *)classforVC{
NSString *classname = NSStringFromClass([classforVC class]);
self.nodeclass = [classtreedic objectForKey:classname];
NSLog(@"self.nodeclass = %@",self.nodeclass);
self.nowclass = [[currectclass alloc] init];
self.nowclass.currclass = classforVC;
self.nowclass.nodeclass = self.nodeclass;
}
只有两个方法。一看就明白。再看这里。
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.
[[Manager shareInstance] loadorganizationformdatainfo];
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
self.window.backgroundColor = [UIColor whiteColor];
ViewController *VC = [[ViewController alloc] init];
self.rootviewcontroller = [[LCNavigationController alloc] initWithRootViewController:VC ];
self.window.rootViewController = self.rootviewcontroller;
[[Manager shareInstance] initforclassname:VC];
return YES;
}
上图中可以看到那俩方法。
//主体调度,单例模式
#import <UIKit/UIKit.h>
#import "Classmodel.h"
@interface currectclass : NSObject
@property(retain,nonatomic) UIViewController *currclass;
@property(retain,nonatomic) Classmodel *nodeclass;
@end
@interface Manager : NSObject
@property(retain,nonatomic) currectclass *nowclass;
@property(retain,nonatomic) Classmodel *nodeclass;
@property(retain,nonatomic) NSMutableDictionary<NSString *, Classmodel *> *classtreedic;
+(instancetype) shareInstance;
-(void) loadorganizationformdatainfo;
-(void) initforclassname:(UIViewController *)classforVC;
@end
classtreedic是解析xml后存放的字典数据。这个本来是考虑写成链表的,但最后考虑没必要那么麻烦。nodeclass就代表xml中每一组<class></class>。nowclass是当前页面活动的对象信息。可看currectclass的定义。Classmodel的定义看这里:
/数据模型,对于datainfo里的一组class具体表现
#import <UIKit/UIKit.h>
@interface ToClassmodel : NSObject
@property (strong, nonatomic) NSString *toclassname;
@end
@interface Classmodel : NSObject
@property (strong, nonatomic) NSString *classname;
@property (nonatomic, retain) NSDictionary<NSString *,ToClassmodel *> *prevclassnamedict;
@property (nonatomic, retain) NSDictionary<NSString *,ToClassmodel *> *nextclassnamedict;
@end
下面介绍Manager+route。这个本来是可写在manager里的。但考虑用分类的话,看起来更清楚一些。下图是方法的定义。有八个方法,一个页面可能会跳向不同的页面,有时还会携带参数。所以就有八个了。
#import "Manager.h"
@interface Manager (route)
-(void)completetonextview;
-(void)completetonextviewfordata:(NSDictionary *)datadic;
-(void)completetonextviewbyid:(NSString *)classid;
-(void)completetonextviewbyid:(NSString *)classid fordata:(NSDictionary *)datadic;
-(void)completetoprevview;
-(void)completetoprevviewfordata:(NSDictionary *)datadic;
-(void)completetoprevviewbyid:(NSString *)classid;
-(void)completetoprevviewbyid:(NSString *)classid fordata:(NSDictionary *)datadic;
@end
#import "Manager+route.h"
#import "Classmodel.h"
#import "AppDelegate.h"
#import "LCNavigationController.h"
#import <objc/runtime.h>
@implementation Manager (route)
-(void)completetonextview{
[self completetonextviewbyid:nil fordata:nil];
}
-(void)completetonextviewfordata:(NSDictionary *)datadic{
[self completetonextviewbyid:nil fordata:datadic];
}
-(void)completetonextviewbyid:(NSString *)classid{
[self completetonextviewbyid:classid fordata:nil];
}
-(void)completetonextviewbyid:(NSString *)classid fordata:(NSDictionary *)datadic{
NSString *Toclassname = [self gettoclassname:classid fordic:self.nowclass.nodeclass.nextclassnamedict];
if (Toclassname == nil) {
return;
}
Class ToClass = NSClassFromString(Toclassname);
[ToClass self];
id obj = [[ToClass alloc] init];
//赋值跳转
if (datadic != nil) {
NSArray *kaylist = [datadic allKeys];
for (NSString *kay in kaylist) {
if ([self getVariableWithClass:ToClass varName:kay]) {
[obj setValue:[datadic objectForKey:kay] forKey:kay];
}
}
}
AppDelegate *app =(AppDelegate *) [UIApplication sharedApplication].delegate;
LCNavigationController *rootViewController = (LCNavigationController *)(app.window.rootViewController);
[rootViewController pushViewController:obj];
//记录当前对象
self.nowclass.currclass = obj;
self.nowclass.nodeclass = [self.classtreedic objectForKey:Toclassname];
}
-(void)completetoprevview{
[self completetoprevviewbyid:nil fordata:nil];
}
-(void)completetoprevviewfordata:(NSDictionary *)datadic{
[self completetoprevviewbyid:nil fordata:datadic];
}
-(void)completetoprevviewbyid:(NSString *)classid{
[self completetoprevviewbyid:classid fordata:nil];
}
-(void)completetoprevviewbyid:(NSString *)classid fordata:(NSDictionary *)datadic{
NSString *Toclassname = [self gettoclassname:classid fordic:self.nowclass.nodeclass.prevclassnamedict];
if (Toclassname == nil) {
return;
}
Class ToClass = NSClassFromString(Toclassname);
[ToClass self];
id obj = [[ToClass alloc] init];
//赋值跳转
if (datadic != nil) {
NSArray *kaylist = [datadic allKeys];
for (NSString *kay in kaylist) {
if ([self getVariableWithClass:ToClass varName:kay]) {
[obj setValue:[datadic objectForKey:kay] forKey:kay];
}
}
}
AppDelegate *app =(AppDelegate *) [UIApplication sharedApplication].delegate;
LCNavigationController *rootViewController = (LCNavigationController *)(app.window.rootViewController);
[rootViewController popToViewController:obj];
//记录当前对象
self.nowclass.currclass = obj;
self.nowclass.nodeclass = [self.classtreedic objectForKey:Toclassname];
}
-(NSString *) gettoclassname:(NSString *)classid fordic:(NSDictionary *)dic{
if (dic.count == 0) {
return nil;
}
if (dic.count == 1) {
return (NSString *)(dic.allValues[0]);
}
return (NSString *)[dic objectForKey:classid];
}
//判断是否包含一个属性
- (BOOL) getVariableWithClass:(Class) myClass varName:(NSString *)name{
unsigned int outCount, i;
Ivar *ivars = class_copyIvarList(myClass, &outCount);
for (i = 0; i < outCount; i++) {
Ivar property = ivars[i];
NSString *keyName = [NSString stringWithCString:ivar_getName(property) encoding:NSUTF8StringEncoding];
keyName = [keyName stringByReplacingOccurrencesOfString:@"_" withString:@""];
if ([keyName isEqualToString:name]) {
return YES;
}
} return NO;
}
@end
上图可看到具体的处理。就是利用反射原理创建所要跳转的对象。然后把参数赋值过去,最后用到LCNavigationController进行跳转。再把当前活动的对象信息(nowclass)更新。
好了,就这些,代码不多,基本能用,但不够完善。后续再完善吧。有大牛看到欢迎指点,以使我进步。