最近項目活比較少,沒事寫了一個框架,也是對之前開發的總結。那我寫這個是幹嗎用呢? 我把app中頁面的跳轉用xml描述,程序會自動解析,各頁面對象的建立也由框架管理建立,這樣由老大搞好流程,下面小弟就只關心各自負責的頁面功能開發就行。低耦合,高內聚。 先看下圖。其中frame是核心部分。另外借用了第三方LCNavigationController和GDataXML。前者是頁面跳轉,後者是xml解析。如何使用自行百度。node
上圖中的datainfo.xml文件就是頁面跳轉的邏輯描述。app
是這個樣子:框架
<?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>是返回上一個頁面。結構仍是很簡單的。ide
Manager是單例類(單例怎麼寫,不用我介紹了)。主要是解析xml文件和初始化。看截圖:atom
-(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; }
只有兩個方法。一看就明白。再看這裏。code
- (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; }
上圖中能夠看到那倆方法。orm
//主體調度,單例模式 #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的定義看這裏:xml
/數據模型,對於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)更新。blog
好了,就這些,代碼很少,基本能用,但不夠完善。後續再完善吧。有大牛看到歡迎指點,以使我進步。