在介绍小项目之前,在此说明一下此代码并非本人所写,我只是随笔的整理者。
在介绍之前先展现一下效果图。

看过效果图大家应该很熟悉了,就是饿了么的一个界面而已,值得注意的是,实现时并没有采用本地连接,而是实打实的网络连接。看一下文件架构。

这一采用的是MVC设计模式,虽然文件很少,但是也可以看。
下面开始正式介绍小项目的实现。
首先介绍Model的实现,很简单,实现模型即可,
// // Shop.h // CX-小项目(饿了么 网络部分 简单实现) // // Created by ma c on 16/3/23. // Copyright ? 2016年 xubaoaichiyu. All rights reserved. // #import <Foundation/Foundation.h> @interface Shop : NSObject //建立Shop模型 @property (nonatomic, copy) NSString * address; @property (nonatomic, copy) NSString * name; @property (nonatomic, copy) NSString * image_path; //-description这个方法系统占用 @property (nonatomic, copy) NSString * desc; @end
// // Shop.m // CX-小项目(饿了么 网络部分 简单实现) // // Created by ma c on 16/3/23. // Copyright ? 2016年 xubaoaichiyu. All rights reserved. // #import "Shop.h" @implementation Shop @end
model实现后我们并没有真正的实现方法,下面也不是,接下来是对AFN的封装,之所以封装是因为,我们难以保证在以后该三方还能存在,只要封装,哪怕以后没有了AFN我们也可以在封装框架里运用其他的三方实现。
//
// HttpClient.h
// CX-小项目(饿了么 网络部分 简单实现)
//
// Created by ma c on 16/3/23.
// Copyright ? 2016年 xubaoaichiyu. All rights reserved.
//
#import <Foundation/Foundation.h>
#import "AFNetworking.h"
//HTTP请求类别
typedef NS_ENUM(NSInteger,HttpRequestType) {
HttpRequestGet,
HttpRequestPost,
HttpRequestPut,
HttpRequestDelete,
};
/**
* 请求前预处理block
*/
typedef void(^PrepareExecuteBlock)(void);
typedef void(^SuccessBlock)(NSURLSessionDataTask * task, id responseObject);
typedef void(^FailureBlock)(NSURLSessionDataTask * task, NSError * error);
@interface HttpClient : NSObject
+ (HttpClient *)defaultClient;
/**
* HTTP请求(GET,POST,PUT,DELETE)
*
* @param url 请求地址
* @param method 请求类型
* @param params 请求参数
* @param prepare 请求前预处理
* @param success 请求成功处理
* @param failure 请求失败处理
*/
- (void)requestWithPath:(NSString *)url
method:(NSInteger)method
paramenters:(NSDictionary *)params
prepareExecute:(PrepareExecuteBlock)prepare
success:(SuccessBlock)success
failure:(FailureBlock)failure;
@end
//
// HttpClient.m
// CX-小项目(饿了么 网络部分 简单实现)
//
// Created by ma c on 16/3/23.
// Copyright ? 2016年 xubaoaichiyu. All rights reserved.
//
#import "HttpClient.h"
@interface HttpClient ()
@property (nonatomic, strong) AFHTTPSessionManager * manager;
@property (nonatomic, assign) BOOL isConnect;
@end
@implementation HttpClient
- (instancetype)init
{
self = [super init];
if (self) {
self.manager = [AFHTTPSessionManager manager];
//设置请求类型
self.manager.requestSerializer = [AFHTTPRequestSerializer serializer];
//设置响应类型
self.manager.responseSerializer = [AFJSONResponseSerializer serializer];
self.manager.responseSerializer.acceptableContentTypes = [NSSet setWithObjects:@"application/json",@"text/html", @"text/json", @"text/javascript",@"text/plain",@"image/gif", nil];
//开启监听
[self openNetMonitoring];
}
return self;
}
//判断是否有网络连接,有网络连接再进行下一操作。
- (void)openNetMonitoring {
[[AFNetworkReachabilityManager sharedManager] setReachabilityStatusChangeBlock:^(AFNetworkReachabilityStatus status) {
switch (status) {
case AFNetworkReachabilityStatusUnknown:
self.isConnect = NO;
break;
case AFNetworkReachabilityStatusNotReachable:
self.isConnect = NO;
break;
case AFNetworkReachabilityStatusReachableViaWiFi:
self.isConnect = YES;
break;
case AFNetworkReachabilityStatusReachableViaWWAN:
self.isConnect = YES;
break;
default:
break;
}
}];
[[AFNetworkReachabilityManager sharedManager] startMonitoring];
self.isConnect = YES;
}
//单例
+ (HttpClient *)defaultClient {
static HttpClient * instance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
instance = [[self alloc] init];
});
return instance;
}
- (void)requestWithPath:(NSString *)url
method:(NSInteger)method
paramenters:(NSDictionary *)params
prepareExecute:(PrepareExecuteBlock)prepare
success:(SuccessBlock)success
failure:(FailureBlock)failure {
if ([self isConnectionAvailable]) {
//预处理
if (prepare) {
prepare();
}
switch (method) {
case HttpRequestGet:
[self.manager GET:url parameters:params progress:nil success:success failure:failure];
break;
case HttpRequestPost:
[self.manager POST:url parameters:params progress:nil success:success failure:failure];
break;
case HttpRequestPut:
[self.manager PUT:url parameters:params success:success failure:failure];
break;
case HttpRequestDelete:
[self.manager DELETE:url parameters:params success:success failure:failure];
break;
default:
break;
}
} else {
[self showExceptionDialog];
}
}
- (BOOL)isConnectionAvailable {
return self.isConnect;
}
//如果,没有网络,弹出Alert
- (void)showExceptionDialog {
[[[UIAlertView alloc] initWithTitle:@"提示" message:@"网络连接异常,请检查网络连接" delegate:nil cancelButtonTitle:@"好的" otherButtonTitles: nil] show];
}
@end
接下来是对SVProgressHUD进行封装
// // ToolHelper.h // CX-小项目(饿了么 网络部分 简单实现) // // Created by ma c on 16/3/23. // Copyright ? 2016年 xubaoaichiyu. All rights reserved. // #import <Foundation/Foundation.h> @interface ToolHelper : NSObject /******************* 指示器方法 ****************/ //对指示器进行封装,如可出现新的主流三方,可以很好的给予升级 //弹出操作错误信息提示框 + (void)showErrorMessage:(NSString *)message; //弹出操作成功信息提示框 + (void)showSuccessMessage:(NSString *)message; //弹出加载提示框 + (void)showProgressMessage:(NSString *)message; //弹出用户信息 + (void)showInfoMessage:(NSString *)message; //取消弹出框 + (void)dismissHUD; @end
//
// ToolHelper.m
// CX-小项目(饿了么 网络部分 简单实现)
//
// Created by ma c on 16/3/23.
// Copyright ? 2016年 xubaoaichiyu. All rights reserved.
//
#import "ToolHelper.h"
#import "SVProgressHUD.h"
@implementation ToolHelper
//弹出操作错误信息提示框
+ (void)showErrorMessage:(NSString *)message {
[SVProgressHUD showErrorWithStatus:message];
}
//弹出操作成功信息提示框
+ (void)showSuccessMessage:(NSString *)message {
[SVProgressHUD showSuccessWithStatus:message];
}
//弹出加载提示框
+ (void)showProgressMessage:(NSString *)message {
[SVProgressHUD showWithStatus:message];
}
//弹出用户信息
+ (void)showInfoMessage:(NSString *)message {
[SVProgressHUD showInfoWithStatus:message];
}
//取消弹出框
+ (void)dismissHUD {
[SVProgressHUD dismiss];
}
@end
做完以上工作之后下面需要解决的便是上面遗留下来的问题,不知道大家有没有发现在model里的注释
//-description这个方法系统占用
我们该怎么解决这个问题呢,那么我要说的便是三方啦。
MJ的三方解决了这一问题
// // MJExtensionConfig.h // CX-小项目(饿了么 网络部分 简单实现) // // Created by ma c on 16/3/23. // Copyright ? 2016年 xubaoaichiyu. All rights reserved. // #import <Foundation/Foundation.h> @interface MJExtensionConfig : NSObject @end
//
// MJExtensionConfig.m
// CX-小项目(饿了么 网络部分 简单实现)
//
// Created by ma c on 16/3/23.
// Copyright ? 2016年 xubaoaichiyu. All rights reserved.
//
#import "MJExtensionConfig.h"
#import "MJExtension.h"
#import "Shop.h"
@implementation MJExtensionConfig
//程序启动一定会调用
+ (void)load {
/**
* 解决网络的JSON字段和本地模型属性名不一致的情况
*
* @return 左边是本地属性名,右侧是网络JSON名
*/
[Shop mj_setupReplacedKeyFromPropertyName:^NSDictionary *{
return @{@"desc" : @"description"};
}];
}
@end
(对于load在前面的博客我有详细的解释,不清楚的朋友可以看看)
处理过后,为了方便对整个程序都能用到的便俩个 头文件进行优化,我们采用PCH文件
// // ELeMe.pch // CX-小项目(饿了么 网络部分 简单实现) // // Created by ma c on 16/3/23. // Copyright ? 2016年 xubaoaichiyu. All rights reserved. // #ifndef ELeMe_pch #define ELeMe_pch #ifdef __OBJC__ #import <UIKit/UIKit.h> #import <Foundation/Foundation.h> #endif #import "ToolHelper.h" /***************SERVER HOST***************/ #define SERVER_HOST @"http://restapi.ele.me/v3" /***************SERVER API***************/ //获取餐馆列表 #define API_GetRestaurantsList @"/restaurants" #define SCREEN_WIDTH [UIScreen mainScreen].bounds.size.width #define SCREEN_HEIGHT [UIScreen mainScreen].bounds.size.height #define shopInfoPageLimit 20 #endif /* ELeMe_pch */
写完代码我们需要设置一下
设置如下

其实整个小项目真的很简单,导致并没有什么可以仔细去想的,写多了就好了。
下面是主要环节(注释说明的很详尽了,我就不多说废话了)
// // ViewController.h // CX-小项目(饿了么 网络部分 简单实现) // // Created by ma c on 16/3/23. // Copyright ? 2016年 xubaoaichiyu. All rights reserved. // #import <UIKit/UIKit.h> @interface ViewController : UIViewController @end
//
// ViewController.m
// CX-小项目(饿了么 网络部分 简单实现)
//
// Created by ma c on 16/3/23.
// Copyright ? 2016年 xubaoaichiyu. All rights reserved.
//
#import "ViewController.h"
#import "HttpClient.h"
#import "SVProgressHUD.h"
#import "Shop.h"
#import "MJExtension.h"
#import "ShopIconCell.h"
#import "MJRefresh.h"
static NSString * identifier = @"ShopInfoCell";
@interface ViewController ()<UITableViewDataSource,UITableViewDelegate>
//分页的页数
@property (nonatomic, assign) NSInteger page;
@property (nonatomic, strong) UITableView * tableView;
@property (nonatomic, strong) NSMutableArray * dataList;
@end
@implementation ViewController
- (NSMutableArray *)dataList {
if (!_dataList) {
_dataList = [NSMutableArray array];
}
return _dataList;
}
- (UITableView *)tableView {
if (!_tableView) {
_tableView = [[UITableView alloc] initWithFrame:self.view.bounds style:UITableViewStylePlain];
_tableView.dataSource =self;
_tableView.delegate =self;
[_tableView registerClass:[ShopInfoCell class] forCellReuseIdentifier:identifier];
_tableView.rowHeight = 80;
}
return _tableView;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return self.dataList.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
ShopInfoCell * cell = [tableView dequeueReusableCellWithIdentifier:identifier];
cell.shop = self.dataList[indexPath.row];
return cell;
}
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
[self.view addSubview:self.tableView];
//使用MJRefresh给我们的talbleView添加下拉刷新上拉加载控件
self.tableView.mj_header = [MJRefreshNormalHeader headerWithRefreshingTarget:self refreshingAction:@selector(loadNewData)];
self.tableView.mj_footer = [MJRefreshBackNormalFooter footerWithRefreshingTarget:self refreshingAction:@selector(loadMoreData)];
// [self loadNewData];
//进入界面执行下拉刷新方法
[self.tableView.mj_header beginRefreshing];
}
//上拉加载更多
- (void)loadMoreData {
NSString * urlString = [NSString stringWithFormat:@"%@%@",SERVER_HOST,API_GetRestaurantsList];
NSDictionary * params = @{@"full_image_path":@"1",
@"geohash":@"wx4u14w0649y",
@"limit":@(shopInfoPageLimit),
@"offset":@(self.page * shopInfoPageLimit),
@"type":@"geohash",
@"extras[]":@"food_activity",
@"extras[]":@"restaurant_activity"};
[[HttpClient defaultClient] requestWithPath:urlString method:HttpRequestGet paramenters:params prepareExecute:^{
[ToolHelper showProgressMessage:@"我在刷新"];
} success:^(NSURLSessionDataTask *task, id responseObject) {
NSLog(@"%@",responseObject);
//JSON -> MODEL 有很多框架,原理都是KVC.
//MJExtenstion JsonModel Mantle YYModel
//请求的分页数据 +1
//当返回到数据的count值为0时,说明已经全部加载完毕。
NSArray * shopList = [Shop mj_objectArrayWithKeyValuesArray:responseObject];
// if (shopList.count == 0) {
//
// //显示已经全部加载完毕
// [self.tableView.mj_footer endRefreshingWithNoMoreData];
// }
if (self.page > 2) {
[self.tableView.mj_footer endRefreshingWithNoMoreData];
} else {
[self.dataList addObjectsFromArray:shopList];
[self.tableView reloadData];
//将上拉加载控件弹下去
[self.tableView.mj_footer endRefreshing];
self.page ++ ;
}
[ToolHelper showSuccessMessage:@"请求成功"];
} failure:^(NSURLSessionDataTask *task, NSError *error) {
NSLog(@"%@",error);
//将上拉加载控件弹下去
[self.tableView.mj_footer endRefreshing];
[ToolHelper showErrorMessage:@"请求失败"];
}];
}
//下拉刷新
- (void)loadNewData {
NSString * urlString = [NSString stringWithFormat:@"%@%@",SERVER_HOST,API_GetRestaurantsList];
//下拉刷新,上拉加载 请求的地址是一样的 ,只是参数不一样的。
//limit 是不变的、改变 offset。。
//
//下拉刷新是加载最新数据,将page页数至为0.
//上拉加载加载更多数据。将page++
//MJRefresh EGO下拉刷新 UIRefreshCotrol 自已写上拉下拉
NSDictionary * params = @{@"full_image_path":@"1",
@"geohash":@"wx4u14w0649y",
@"limit":@(shopInfoPageLimit),
@"offset":@(0),
@"type":@"geohash",
@"extras[]":@"food_activity",
@"extras[]":@"restaurant_activity"};
[[HttpClient defaultClient] requestWithPath:urlString method:HttpRequestGet paramenters:params prepareExecute:^{
[ToolHelper showProgressMessage:@"我在刷新"];
} success:^(NSURLSessionDataTask *task, id responseObject) {
NSLog(@"%@",responseObject);
//JSON -> MODEL 有很多框架,原理都是KVC.
//MJExtenstion JsonModel Mantle YYModel
//请求的分页数据 +1
self.page = 1 ;
//获取最新数据前删除之前的所有数据
[self.dataList removeAllObjects];
NSArray * shopList = [Shop mj_objectArrayWithKeyValuesArray:responseObject];
[self.dataList addObjectsFromArray:shopList];
[self.tableView reloadData];
//重置没有更多的数据(消除没有更多数据的状态)
[self.tableView.mj_footer resetNoMoreData];
//将下拉刷新控件弹上去
[self.tableView.mj_header endRefreshing];
[ToolHelper showSuccessMessage:@"请求成功"];
} failure:^(NSURLSessionDataTask *task, NSError *error) {
NSLog(@"%@",error);
//将下拉刷新控件弹上去
[self.tableView.mj_header endRefreshing];
[ToolHelper showErrorMessage:@"请求失败"];
}];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
@end
大家是不是觉得少了些什么,当然是cell的自定义了,蛮简单了。看看就好。
// // ShopIconCell.h // CX-小项目(饿了么 网络部分 简单实现) // // Created by ma c on 16/3/23. // Copyright ? 2016年 xubaoaichiyu. All rights reserved. // #import <UIKit/UIKit.h> #import <UIKit/UIKit.h> #import "Shop.h" @interface ShopInfoCell : UITableViewCell @property (nonatomic, strong) Shop * shop; @end
//
// ShopIconCell.m
// CX-小项目(饿了么 网络部分 简单实现)
//
// Created by ma c on 16/3/23.
// Copyright ? 2016年 xubaoaichiyu. All rights reserved.
//
#import "ShopIconCell.h"
#import "UIImageView+WebCache.h"
static CGFloat kMargin = 5;
@interface ShopInfoCell ()
@property (nonatomic, strong) UIImageView * iconView;
@property (nonatomic, strong) UILabel * nameLabel;
@property (nonatomic, strong) UILabel * descLabel;
@end
@implementation ShopInfoCell
- (void)setShop:(Shop *)shop {
_shop = shop;
[self.iconView sd_setImageWithURL:[NSURL URLWithString:shop.image_path] placeholderImage:nil];
self.nameLabel.text = shop.name;
self.descLabel.text = shop.desc;
}
- (UIImageView *)iconView {
if (!_iconView) {
_iconView = [[UIImageView alloc] init];
}
return _iconView;
}
- (UILabel *)nameLabel {
if (!_nameLabel) {
_nameLabel = [[UILabel alloc] init];
}
return _nameLabel;
}
- (UILabel *)descLabel {
if (!_descLabel) {
_descLabel = [[UILabel alloc] init];
}
return _descLabel;
}
-(instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {
if (self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]) {
[self.contentView addSubview:self.iconView];
[self.contentView addSubview:self.nameLabel];
[self.contentView addSubview:self.descLabel];
}
return self;
}
- (void)layoutSubviews {
[super layoutSubviews];
self.iconView.frame = CGRectMake(kMargin, kMargin, 70, 70);
self.nameLabel.frame = CGRectMake(CGRectGetMaxX(self.iconView.frame) + kMargin, CGRectGetMinY(self.iconView.frame), SCREEN_WIDTH - CGRectGetMaxX(self.iconView.frame) - 2 * kMargin, 20);
self.descLabel.frame = CGRectMake(CGRectGetMinX(self.nameLabel.frame), CGRectGetMaxY(self.nameLabel.frame) + kMargin, CGRectGetWidth(self.nameLabel.frame), 20);
}
- (void)awakeFromNib {
}
- (void)setSelected:(BOOL)selected animated:(BOOL)animated {
[super setSelected:selected animated:animated];
}
@end
就这样一个小项目就这么的完成了。
原文:http://www.cnblogs.com/wuyuxin/p/7045608.html