iOS新闻客户端开发教程3--基类编写

来源:互联网 时间:1970-01-01

在面向对象编程中,常用的就是抽象和封装,今天来完成Model,ViewModel,ViewController的编写。

日志宏定义

Model基类

ViewModel基类

ViewController基类

日志宏定义

为了更好查看日志信息,我们封装了一些宏定义,取代了NSLog,让日志信息更方便我们调试

新建Defineds.h

[code]#if (DEBUG || TESTCASE)#define Log(format, ...) NSLog(format, ## __VA_ARGS__)#else#define Log(format, ...)#endif// 日志输出宏#define BASE_LOG(cls,sel) Log(@"%@-%@",NSStringFromClass(cls), NSStringFromSelector(sel))#define BASE_ERROR_LOG(cls,sel,error) Log(@"ERROR:%@-%@-%@",NSStringFromClass(cls), NSStringFromSelector(sel), error)#define BASE_INFO_LOG(cls,sel,info) Log(@"INFO:%@-%@-%@",NSStringFromClass(cls), NSStringFromSelector(sel), info)// 日志输出函数#if (DEBUG || TESTCASE)#define BASE_LOG_FUN() BASE_LOG([self class], _cmd)#define BASE_ERROR_FUN(error) BASE_ERROR_LOG([self class],_cmd,error)#define BASE_INFO_FUN(info) BASE_INFO_LOG([self class],_cmd,info)#else#define BASE_LOG_FUN()#define BASE_ERROR_FUN(error)#define BASE_INFO_FUN(info)#endif


Model基类

在本项目中,Model命名规则都以”对象名称”+Info来命名,我们编写Model基类,新建BaseInfo类

BaseInfo.h

[code]#import <Foundation/Foundation.h>@interface BaseInfo : NSObject@property(nonatomic,strong) NSString *ID;@property(nonatomic,strong) NSString *name;/// 初始化方法-(instancetype) initWithDict:(NSDictionary *) dict;/// 初始化方法+(instancetype) infoWithDict:(NSDictionary *) dict;/// 字典转NSArray+(NSArray *) arrayFromDict:(NSDictionary *) dict;/// 将数组转成对象数组+(NSArray *) arrayFromArray:(NSArray *) array;@end


BaseInfo.m

[code]#import "BaseInfo.h"@implementation BaseInfo-(instancetype) initWithDict:(NSDictionary *)dict{ if (self = [super init]) {self.ID = [dict objectForKey:@"id"];self.name = [dict objectForKey:@"name"];//[self setValuesForKeysWithDictionary:dict];简洁写法 } return self;}+(instancetype) infoWithDict:(NSDictionary *)dict{ return [[self alloc] initWithDict:dict];}+(NSArray *) arrayFromDict:(NSDictionary *) dict{ NSArray *array = [dict objectForKey:NetData]; return [self arrayFromArray:array];}+(NSArray *) arrayFromArray:(NSArray *) array{ NSMutableArray *infos = [[NSMutableArray alloc] init]; for (NSDictionary *dict in array) {[infos addObject:[self infoWithDict:dict]]; } if(infos.count == 0){return nil; } return infos;}@end


Model一般是负责数据传输,充当DTO的角色,它往往是请求服务器接口的返回结果的封装,假设我们服务器的程序接口返回的数据包含ID和name参数,那么我们定义类时,也同样定义2个属性ID和name。

在BaseInfo中,定义了以NSDictionary初始化对象的方法infoWithDict,arrayFromDict,也是OC中常用的初始化对象方法之一。

ViewModel基类

ViewModel负责View和Model间的数据转换,常用的业务操作等。我们在这里定义它是的使命是负责网络请求,并把返回结果封装成Model类。

定义BaseOpertation类

BaseOpertation.h

[code]#import <Foundation/Foundation.h>@protocol BaseOperationDelegate;@interface BaseOperation : NSObject{//声明变量,不能通过点语法设置和获取变量 id<BaseOperationDelegate> _delegate; NSURLConnection *_connection; NSMutableData *_receiveData;//NSMutableData可变的字节操作类 NSInteger _statusCode; long long _totalLength;//双长整型 //默认是@protected@public NSDictionary *_opInfo;}-(id)initWithDelegate:(id<BaseOperationDelegate>) delegate opInfo:(NSDictionary *) opInfo;-(NSMutableURLRequest *) urlRequest;- (void)executeOp;- (void)cancelOp;- (void)parseData:(id)data;- (void)parseSuccess:(NSDictionary *)dict jsonString:(NSString *)jsonString;- (void)parseFail:(id)dict;- (void)parseProgress:(long long)receivedLength;- (NSTimeInterval)timeoutInterval;@end@protocol BaseOperationDelegate <NSObject>-(void)opSuccess:(id)data;-(void)opFail:(NSString *) errorMsg;@optional- (void)opSuccessEx:(id)data opinfo:(NSDictionary *)dictInfo;- (void)opFailEx:(NSString *)errorMessage opinfo:(NSDictionary *)dictInfo;- (void)opSuccessMatch:(id)data;- (void)opUploadSuccess;@end


BaseOperation.m

[code]#import "BaseOperation.h"@implementation BaseOperation-(id)initWithDelegate:(id<BaseOperationDelegate>)delegate opInfo:(NSDictionary *)opInfo{ if(self = [super init]){_delegate = delegate;_opInfo = opInfo;_totalLength = 0; } return self;}- (void)cancelOp{ if (_connection != nil) {BASE_INFO_FUN(@"_connection dealloc cancel");[_connection cancel]; } _connection = nil;}- (void)dealloc{ if (_connection != nil) {BASE_INFO_FUN(@"_connection dealloc cancel");[_connection cancel]; } _connection = nil; _delegate = nil;}- (NSTimeInterval)timeoutInterval{ return FxRequestTimeout;}-(NSMutableURLRequest *)urlRequest{ NSString *urlString = [_opInfo objectForKey:@"url"]; BASE_INFO_FUN(urlString); id body = [_opInfo objectForKey:@"body"]; NSURL *url = [NSURL URLWithString:urlString]; NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url]; if (body != nil) {[request setHTTPMethod:HTTPPOST];if ([body isKindOfClass:[NSString class]]) { [request setHTTPBody:[body dataUsingEncoding:NSUTF8StringEncoding]];}else{ [request setHTTPBody:body];} }else{[request setHTTPMethod:HTTPGET]; } return request;}//使用delegate异步发送请求- (void)executeOp{ _connection = [[NSURLConnection alloc] initWithRequest:[self urlRequest] delegate:self];}- (void)parseData:(NSData *)data{ if (data.length == 0) {[self parseSuccess:nil jsonString:nil];return; } NSString *jsonString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; NSMutableDictionary *dict = [JsonUtility jsonValueFromString:jsonString]; NSString *result = [dict objectForKey:NetResult]; if ([result isEqualToString:NetOk]) {[self parseSuccess:dict jsonString:jsonString]; }else{[self parseFail:dict]; } _receiveData = nil;}- (void)parseSuccess:(NSDictionary *)dict jsonString:(NSString *)jsonString{ [_delegate opSuccess:dict];}- (void)parseFail:(id)dict{ if ([dict isKindOfClass:[NSString class]]) {[_delegate opFail:(NSString *)dict];return; } if ([[dict objectForKey:NetResult] isEqualToString:NetInvalidateToken]) {BASE_ERROR_FUN(NetInvalidateToken); } [_delegate opFail:[dict objectForKey:NetMessage]];}- (void)parseProgress:(long long)receivedLength{}#pragma mark NSURLConnectionDelegage methods// 收到回应- (void)connection:(NSURLConnection *)aConnection didReceiveResponse:(NSURLResponse *)aResponse{ NSHTTPURLResponse *response = (NSHTTPURLResponse *)aResponse; NSString *statusCode = [NSString stringWithFormat:@"%ld",(long)[response statusCode]]; _statusCode = [statusCode intValue]; _receiveData = [[NSMutableData alloc] init]; if (_statusCode == 200 || _statusCode == 206) {_totalLength = [response expectedContentLength]; } BASE_INFO_FUN(statusCode);}// 接收数据- (void)connection:(NSURLConnection *)aConn didReceiveData:(NSData *)data{ BASE_INFO_FUN(([NSString stringWithFormat:@"%lu", (unsigned long)data.length])); [_receiveData appendData:data]; [self parseProgress:_receiveData.length];}// 数据接收完毕- (void)connectionDidFinishLoading:(NSURLConnection *)aConn{ BASE_INFO_FUN([[NSString alloc] initWithData:_receiveData encoding:NSUTF8StringEncoding]); // 成功接受:200有数据,204没有数据,206断点续传 if (_statusCode == 200 || _statusCode == 204 || _statusCode == 206) {[self parseData:_receiveData]; } else {NSString *errorMessage = [[NSString alloc] initWithData:_receiveData encoding:NSUTF8StringEncoding];if (errorMessage.length <= 0) { errorMessage = [[NSString alloc] initWithFormat:@"ResponseCode:%ld", (long)_statusCode];}[self parseFail:errorMessage]; } _connection = nil; _receiveData = nil;}// 返回错误- (void)connection:(NSURLConnection *)aConn didFailWithError:(NSError *)error{ [self parseFail:[error localizedDescription]]; _connection = nil; _receiveData = nil;}@end


在BaseOperation类中,使用了OC原生的网络请求类URL,URLRequest,URLConnection来异步请求网络,并将请求的结果封装成NSMutableDictionary传递给OpSuccess方法。在子类中,我们可以复写OpSuccess方法来接收参数完成对具体Model的封装。

ViewController基类

ViewController基类负责将ViewModel和View(xib)之间交互,完成UI界面展示,数据填充,事件响应等功能。

新建BaseController类

BaseController.h

[code]//// BaseController.h// NewsReader//// Created by 唐有欢 on 15/10/13.// Copyright © 2015年 tangtech. All rights reserved.//#import <UIKit/UIKit.h>#import "BaseOperation.h"#import "Activity.h"@interface BaseController : UIViewController<BaseOperationDelegate>{ BaseOperation *_operation; Activity *_activity;}- (void)showIndicator:(NSString *)tipMessage autoHide:(BOOL)hide afterDelay:(BOOL)delay;- (void)hideIndicator;// 导航栏设置- (void)setNavigationTitleImage:(NSString *)imageName;- (void)setNavigationLeft:(NSString *)imageName sel:(SEL)sel;- (void)setNavigationRight:(NSString *)imageName;- (void)setStatusBarStyle:(UIStatusBarStyle)style;- (void)opSuccess:(id)data;@end


BaseController.m

[code]#import "BaseController.h"#import "ActivityIndicator.h"@implementation BaseController-(void)viewDidLoad{ [super viewDidLoad]; [self setNavigationLeft:@"NavigationBell.png" sel:nil]; [self setNavigationRight:@"NavigationSquare.png"]; //[self setNavigationTitleImage:@"NavBarIcon.png"];}-(void)viewWillAppear:(BOOL)animated{ [super viewWillAppear:animated]; [self setNavBarImage]; [[UIApplication sharedApplication] setStatusBarHidden:NO]; [self setStatusBarStyle:UIStatusBarStyleLightContent];}- (Activity *)showActivityInView:(UIView *)view{ Activity *activity = [[ActivityIndicator alloc] initWithView:view]; CGRect frame = view.bounds; activity.frame = frame; [view addSubview:activity]; activity.labelText = @""; return activity;}- (void)showIndicator:(NSString *)tipMessage autoHide:(BOOL)hide afterDelay:(BOOL)delay{ if (_activity == nil) {_activity = [self showActivityInView:self.view]; } if (tipMessage != nil) {_activity.labelText = tipMessage;[_activity show:NO]; } if (hide && _activity.alpha>=1.0) {if (delay) [_activity hide:YES afterDelay:AnimationSecond];else [_activity hide:YES]; }}- (void)hideIndicator{ [_activity hide:YES];}- (void)setNavBarImage{ UIImage *image = [UIImage imageNamed:[Global isSystemLowIOS7]?@"NavigationBar44.png":@"NavigationBar64.png"]; [self.navigationController.navigationBar setBackgroundImage:image forBarMetrics:UIBarMetricsDefault]; [self.navigationController.navigationBar setTintColor:[UIColor whiteColor]]; NSDictionary *attribute = @{NSForegroundColorAttributeName:[UIColor whiteColor],NSFontAttributeName:[UIFont systemFontOfSize:18]}; [self.navigationController.navigationBar setTitleTextAttributes:attribute];}- (UIButton *)customButton:(NSString *)imageName selector:(SEL)sel{ UIButton *btn = [UIButton buttonWithType:UIButtonTypeCustom]; btn.frame = CGRectMake(0, 0, 44, 44); [btn setImage:[UIImage imageNamed:imageName] forState:UIControlStateNormal]; [btn addTarget:self action:sel forControlEvents:UIControlEventTouchUpInside]; return btn;}- (void)setNavigationTitleImage:(NSString *)imageName{ UIImage *image = [UIImage imageNamed:imageName]; UIImageView *imageView = [[UIImageView alloc] initWithImage:image]; self.navigationItem.titleView = imageView;}- (void)setNavigationLeft:(NSString *)imageName sel:(SEL)sel{ UIBarButtonItem *item = [[UIBarButtonItem alloc] initWithCustomView:[self customButton:imageName selector:sel]]; self.navigationItem.leftBarButtonItem = item;}- (void)setNavigationRight:(NSString *)imageName{ UIBarButtonItem *item = [[UIBarButtonItem alloc] initWithCustomView:[self customButton:imageName selector:@selector(doRight:)]]; self.navigationItem.rightBarButtonItem = item;}- (void)setStatusBarStyle:(UIStatusBarStyle)style{ [[UIApplication sharedApplication] setStatusBarStyle:style];}- (void)opSuccess:(id)data{ [self hideIndicator];}- (IBAction)doBack:(id)sender{ [self.navigationController popViewControllerAnimated:YES];}@end


至此,我们定义好了MVVM开发模式的基类,包括:

Model

|

|_ BaseInfo

ViewModel

|

|_BaseOperation

ViewController

|

|_BaseController

在后面的开发过程中就可以更加关注具体功能了。

github源码:https://github.com/tangthis/NewsReader

个人技术分享微信公众号,欢迎关注一起交流



相关阅读:
Top