zoukankan      html  css  js  c++  java
  • IOS-小项目(饿了么 网络部分 简单实现)

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

    在介绍之前先展现一下效果图。

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

    这一采用的是MVC设计模式,虽然文件很少,但是也可以看。

    下面开始正式介绍小项目的实现。

    首先介绍Model的实现,很简单,实现模型即可,

    Shop.h

    复制代码
    //
    //  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

    复制代码
    //
    //  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 HttpClient.m

    复制代码
    //
    //  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进行封装

    TollHeper.h TollHeper.m

    复制代码
    //
    //  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 MJExtensionConfig.m

    复制代码
    //
    //  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

    复制代码
    //
    //  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 ViewController.m

    复制代码
    //
    //  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 ShopIconCell.m

    复制代码
    //
    //  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
    复制代码

    就这样一个小项目就这么的完成了。

  • 相关阅读:
    linux下的进程管理
    linux 下的rpm包管理
    计算机基础之OSI模型 & TCP协议簇
    计算机网络基础-IP分类及划分子网实例
    docker容器可被其他主机访问设置
    redis连接问题
    redis五大类型常用命令-string|list|hash|set|zset-订阅-事务
    docker login & push失败问题记录
    linux下 python 和 pip 安装换源及虚拟环境管理详解
    linux 查看系统版本号
  • 原文地址:https://www.cnblogs.com/wuyuxin/p/7045608.html
Copyright © 2011-2022 走看看