糯米团—重制“iPhone团购信息客户端”(一)

Show
这里写图片描述


前言

    因为是重制的客户端,作者博客中写到的很详细的内容相同的这里不会再写,但会给出提示,对照查看。

iPhone团购信息客户端的开发


目录结构

    由于原作没有按照分层架构设计,所以这里我按照自己想法进行分层架构设计的,不过本来我也是全写在一个文件中的,但是文件过于冗长层次也不清晰所以拆分了两个模块下来,真的是很难拆,要改动很多,所以只拆了两个下来放到BusinessLayer中了。

这里写图片描述


准备工作

  • 首先作者提供的 美团api 地址过久已经失效,故用了 百度糯米api
    • 选择城市生成url就可以拿来使用了
    • 注意像北京上海南京等大城市会取得超大量的数据,直接把地址粘贴到下载工具下载保存成.xml形式,会有七十多兆的大小,而像香港澳门只有200多K
  • 用到的第三方框架有:
    • MBProcessHUD
    • ASIHttpRequest
    • TBXML (原用的KissXML,但我认为TBXML解析更快,而且根本不需要写入的功能,所以更换成更轻量的TBXML,但同样都是基于dom的解析框架。)
    • AQGridView
    • TSPopover (这个框架是我加上去的,因为原app选择城市是读取城市api直接通过segue跳转到UITableView了,而我并没有找到糯米关于城市的api,故只加了一共3个城市,用了TSPopover更美观的显示出来。)
      TSPopover

Let’s do it!

框架导入

仿佛回到了刚刚重制app的时候,当然我不用迷茫,作者已经告诉了我首先要做什么,当然是导入框架!

首先按照iPhone团购信息客户端的开发 (一)做完已经建立了程序主视图并且导入了ASIHttpRequest框架。

    当然不明不白的导入一个不知道起什么作用的框架肯定不行,翻阅资料后确实觉得这个框架挺不错,至少比直接调用系统提供的api简单的多,并且还封装了其它有意思的事情。

导入第一个框架之后,接下来请看iPhone团购信息客户端的开发 (二)
这里告诉你了怎样添加KissXML,MBProgressHUD,AQridView这三个框架,但是注意KissXML请不要导入,导入TBXML,和导入KissXML一样简单,并不需要其它的框架支持。同样的,导入TSPopover框架。

  • 如果导入后发现有错误,请加入pch文件

PrefixHeader.pch

#ifndef PrefixHeader_pch
#define PrefixHeader_pch

#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
#define ARC_ENABLED

#endif 

如不知怎样加入pch文件请移步:Xcode7 建立 pch 文件 (预编译头文件)

  • 遇到缺少GHUnitIOS.framework怎么办?

到github下载gh-unit看Readme进行编译得到framework。


storyboard图

开始写!

OK到了写代码的时候,我也是从主视图的第1个开始写的。

不像原作那样一步步的制作过程都贴上来,程序已经complete,这里只是描述一下制作过程,代码中注释的很详细了,如果有不明白的地方可以贴上来共同探讨 :)

上面这张图片标号分别对应:
1. 主视图
2. 商品详情视图
3. 商家所在地图位置
4. 关于

因为并没有用到数据库什么的,我在PersistenceLayer只存放了地图上标注气泡信息类,可以先不从这里写起,直接从BusinessLogicLayer开始。

BusinessLogicLayer

首先从XML的解析开始

XMLParser.h

#import <Foundation/Foundation.h>
#import "TBXML.h"

@interface XMLParser : NSObject

@property (nonatomic, strong) NSMutableArray *arrays;

@property (nonatomic, readonly) NSString *urlChildOfRootElement;
@property (nonatomic, readonly) NSString *dataChildOfUrlElement;
@property (nonatomic, readonly) NSString *displayChildOfDataElement;

@property (nonatomic, readonly) NSString *tb_siteUrl;
@property (nonatomic, readonly) NSString *tb_title;
@property (nonatomic, readonly) NSString *tb_image;
@property (nonatomic, readonly) NSString *tb_price;

@property (nonatomic, readonly) NSString *tb_shops;
@property (nonatomic, readonly) NSString *tb_shop;
@property (nonatomic, readonly) NSString *tb_shopName;
@property (nonatomic, readonly) NSString *tb_address;
@property (nonatomic, readonly) NSString *tb_longitude;
@property (nonatomic, readonly) NSString *tb_latitude;

- (NSMutableArray *)xmlParser:(NSData *)data;

@end

之所以在这里面写了那么多public属性,是方便主视图的读取,或许这样太乱了,我根本就该写一个类来进行封装!

XMLParser.m

#import "XMLParser.h"

@interface XMLParser () {
    TBXML *tbxml;
}

@end

@implementation XMLParser

- (id)init {
    if (self = [super init]) {
        _urlChildOfRootElement = @"url";
        _dataChildOfUrlElement = @"data";
        _displayChildOfDataElement = @"display";

        _tb_siteUrl = @"wapGoodsURL";
        _tb_title = @"title";
        _tb_image = @"image";
        _tb_price = @"price";

        _tb_shops = @"shops";
        _tb_shop = @"shop";
        _tb_shopName = @"name";
        _tb_address = @"addr";
        _tb_longitude = @"longitude";
        _tb_latitude = @"latitude";
    }
    return self;
}

- (NSMutableArray *)xmlParser:(NSData *)data {

    NSError *err;
    _arrays = [NSMutableArray array];
    //载入XML
    if (data) {
        tbxml = [[TBXML alloc] initWithXMLData:data error:&err];
    } else {
        tbxml = [[TBXML alloc] initWithXMLFile:@"dailydeal.xml" error:&err];
    }

    //读取根点播洋葱
    TBXMLElement *root = tbxml.rootXMLElement;
    if (root) {
        TBXMLElement *url = [TBXML childElementNamed:_urlChildOfRootElement parentElement:root error:&err];
        while (url != nil) {
            TBXMLElement *data = [TBXML childElementNamed:_dataChildOfUrlElement parentElement:url error:&err];
            if (data) {
                TBXMLElement *display = [TBXML childElementNamed:_displayChildOfDataElement parentElement:data error:&err];
                if (display) {
                    NSMutableDictionary *dict = [NSMutableDictionary new];
                    TBXMLElement *siteurl = [TBXML childElementNamed:_tb_siteUrl parentElement:display];
                    if (siteurl) {
                        NSString *siteurlString = [TBXML textForElement:siteurl];
                        [dict setValue:siteurlString forKey:_tb_siteUrl];
                    }
                    TBXMLElement *title = [TBXML childElementNamed:_tb_title parentElement:display];
                    if (title) {
                        NSString *titleString = [TBXML textForElement:title];
                        [dict setValue:titleString forKey:_tb_title];
                    }
                    TBXMLElement *image = [TBXML childElementNamed:_tb_image parentElement:display];
                    if (image) {
                        //此时得到的URL并不能直接解析成图片,需要截取
                        NSString *imageUrl = [TBXML textForElement:image];
                        NSString *tempStr = @"http://e.hiphotos.baidu.com/";
                        NSRange range = [imageUrl rangeOfString:tempStr];
                        NSUInteger location = range.location;
                        //warning 这段代码太冗余了
                        if (location > 1000) {
                            tempStr = @"http://S1.nuomi.bdimg.com/";
                            range = [imageUrl rangeOfString:tempStr];
                            location = range.location;
                            if (location > 1000) {
                                tempStr = @"http://S2.nuomi.bdimg.com/";
                                range = [imageUrl rangeOfString:tempStr];
                                location = range.location;
                                if (location > 1000) {
                                    tempStr = @"http://S0.nuomi.bdimg.com/";
                                    range = [imageUrl rangeOfString:tempStr];
                                    location = range.location;
                                }
                            }
                        }
                        imageUrl = [imageUrl substringFromIndex:location];
                        [dict setValue:imageUrl forKey:_tb_image];
                    }
                    TBXMLElement *price = [TBXML childElementNamed:_tb_price parentElement:display];
                    if (price) {
                        NSString *priceString = @"¥";
                        priceString = [priceString stringByAppendingString:[TBXML textForElement:price]];
                        [dict setValue:priceString forKey:_tb_price];
                    }
                    //店铺字典
                    NSMutableDictionary *dictOfShops = [NSMutableDictionary new];
                    TBXMLElement *shops = [TBXML childElementNamed:_tb_shops parentElement:display];
                    if (shops) {
                        TBXMLElement *shop = [TBXML childElementNamed:_tb_shop parentElement:shops];
                        if (shop) {
                            TBXMLElement *shopName = [TBXML childElementNamed:_tb_shopName parentElement:shop];
                            if (shopName) {
                                NSString *shopNameStr = [TBXML textForElement:shopName];
                                [dictOfShops setValue:shopNameStr forKey:_tb_shopName];
                            }
                            TBXMLElement *shopAddress = [TBXML childElementNamed:_tb_address parentElement:shop];
                            if (shopAddress) {
                                NSString *addressStr = [TBXML textForElement:shopAddress];
                                [dictOfShops setValue:addressStr forKey:_tb_address];
                            }
                            TBXMLElement *shopLongitude = [TBXML childElementNamed:_tb_longitude parentElement:shop];
                            if (shopLongitude) {
                                NSString *longitudeStr = [TBXML textForElement:shopLongitude];
                                [dictOfShops setValue:longitudeStr forKey:_tb_longitude];
                            }
                            TBXMLElement *shopLatitude = [TBXML childElementNamed:_tb_latitude parentElement:shop];
                            if (shopLatitude) {
                                NSString *latitudeStr = [TBXML textForElement:shopLatitude];
                                [dictOfShops setValue:latitudeStr forKey:_tb_latitude];
                            }
                        }
                    }

                    [dict setValue:dictOfShops forKey:_tb_shop];

                    //数据添加到数组
                    [_arrays addObject:dict];
                    //移动到下一个节点开始解析
                    url = [TBXML nextSiblingNamed:_urlChildOfRootElement searchFromElement:url];
                }
            }
        }
    }

    return _arrays;
}

@end

这一段代码是通过TBXML进行的解析,有些地方也比较冗余,或许有更简洁的语法实现,唉,懒得思考……

    这里你看到假如data为nil,我就读取我里面存在的xml文件,这是下载好的南京市的api截取了前20条信息,不然通过网络读取的话网速不好要下载好长时间,当然香港澳门这两地API长度很小可以直接通过网络读取,不过当网速很好的时候你就看不到HUD进度条的动画效果了。

再一个就是图片的处理,把从xml读取到的image地址进行网络请求多线程加载图片。

PicProcessor.h

#import <Foundation/Foundation.h>
#import "ASIHTTPRequest.h"

@class FirstViewController;

@interface PicProcessor : NSObject

@property (nonatomic, strong) NSMutableDictionary *cachedImage;
@property (nonatomic, strong) NSOperationQueue *queue;

- (UIImage *)cachedImageForUrl:(NSURL *)url;

@end

PicProcessor.m

//
//  PicProcessor.m
//  今日糯米团
//
//  Created by Sunny on 12/12/15.
//  Copyright © 2015 IOSDevelopeGuid. All rights reserved.
//

#import "PicProcessor.h"

@implementation PicProcessor

//需要在这里进行初始化
- (id)init {
    if (self = [super init]) {
        _queue = [[NSOperationQueue alloc] init];
        _cachedImage = [NSMutableDictionary dictionary];
    }
    return self;
}

//下载缓存图片处理
- (UIImage *)cachedImageForUrl:(NSURL *)url {
    id cachedObject = [self.cachedImage objectForKey:url];
    if (!cachedObject) {
        [self.cachedImage setObject:@"Loading..." forKey:url]; //添加占位符
        ASIHTTPRequest *picRequest = [ASIHTTPRequest requestWithURL:url];
        picRequest.delegate = self;
        picRequest.didFinishSelector = @selector(didFinishRequestImage:);
        picRequest.didFailSelector = @selector(didFailRequestImage:);
        //加入多线程进行处理
        [_queue addOperation:picRequest];
        [UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
    } else if (![cachedObject isKindOfClass:[UIImage class]]) {
        cachedObject = nil;
    }
    return cachedObject;
}

//下载图片成功
- (void)didFinishRequestImage:(ASIHTTPRequest *)request {
    NSData *imageData = [request responseData];
    UIImage *image = [UIImage imageWithData:imageData];
    if (image) {
        [_cachedImage setObject:image forKey:request.url];
        [[NSNotificationCenter defaultCenter] postNotificationName:@"gridReload" object:nil];
    }
    [UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
}

//下载图片失败
- (void)didFailRequestImage:(ASIHTTPRequest *)request {
    //从当前缓存中移除
    [_cachedImage removeObjectForKey:request.url];
    [UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
}

@end

好了,BusinessLogicLayer主要就是写这两块,也是我费了一段时间拆下来的两块,至于其它的第三方框架和需求库我也放到里面了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值