美文网首页
2017.11tableview 封装 与 webview 缓存

2017.11tableview 封装 与 webview 缓存

作者: 光彩影 | 来源:发表于2017-11-28 20:59 被阅读19次

技术点两点: tableview 封装 与 webview 缓存实现

  1. 刷新tableview封装:MBARefreshTableView(集成mjRefresh与DZNEmpty空视图)。

由于项目出现了tableview重复出现数据或tableview数组越界的bug。所以重新整理思路,对刷新talbeView封装。

10月技术点记录3中,虽然用如下暂时阻止了越界问题。但是 这方案是不可取的,有逻辑错误才会导致此问题。

//即:
 if(self.dataArray.count != 0 && indexPath.row < self.dataArray.count){
Model * model = self.dataArray[indexPath.row];
}

解决如上问题:
主要是上下刷新没有控制好。就是只能存在一个网络数据去请求。(1.多bloading判断,直到请求结束才能bloading改false。2.然后如果在上拉刷新,就控制不让下拉刷新。如果是在下拉刷新,就不让上拉刷新。 即只存在一个刷新在处理

所以从新整理MBARefreshTableView逻辑如下(如有好的建议,欢迎一起探讨):

#import <UIKit/UIKit.h>

@interface MBARefreshTableView : UITableView<MBASkinProtocol, UITableViewDelegate, UITableViewDataSource,DZNEmptyDataSetSource,DZNEmptyDataSetDelegate>

-(void)initUI;
@property (strong, nonatomic) NSMutableArray *mDataItems;
@property (assign, nonatomic) BOOL bHeader;//是否头部请求


@property (assign, nonatomic) BOOL bRefresh;//是否可刷新
@property (assign, nonatomic) BOOL bOnlyHeaderRefresh;
@property (assign, nonatomic) BOOL bOnlyFooterRefresh;

@property (copy, nonatomic) void(^didSelectedHandler)(NSIndexPath *indexPath);

// refresh handler
@property (copy, nonatomic) void(^headerRefreshHandler)(void);
@property (copy, nonatomic) void(^footerRefreshHandler)(void);


// header
- (void)startHeaderRefresh;
- (void)stopHeaderRefresh;
// footer
- (void)startFooterRefresh;
- (void)stopFooterRefresh;

-(void)stopRefresh;

@end
#import "MBARefreshTableView.h"


@implementation MBARefreshTableView

-(instancetype)init
{
    if(self = [super init])
    {
        [self _init];
    }
    return self;
}

-(instancetype)initWithFrame:(CGRect)frame {
    if(self = [super initWithFrame:frame])
    {
        [self _init];
    }
    return self;
}

-(instancetype)initWithFrame:(CGRect)frame style:(UITableViewStyle)style {
    if(self = [super initWithFrame:frame style:style])
    {
        [self _init];
    }
    return self;
}

-(void)_init{
    self.delegate = self;
    self.dataSource = self;
    
    self.emptyDataSetSource = self;
    self.emptyDataSetDelegate = self;
    
    self.separatorInset = UIEdgeInsetsZero;
    if([self respondsToSelector:@selector(cellLayoutMarginsFollowReadableWidth)])
    {
        self.cellLayoutMarginsFollowReadableWidth = false;
    }
    
    //刷新操作只能一个
    MBAWeakSelf
    MJRefreshNormalHeader *header = [MJRefreshNormalHeader headerWithRefreshingBlock:^{
        if([weakSelf.mj_footer isRefreshing]){
            [weakSelf.mj_header endRefreshing];
            return;
        }
        [weakSelf handlerHeaderRefresh];
        if(weakSelf.headerRefreshHandler) weakSelf.headerRefreshHandler();
    }];

    self.mj_footer = [MJRefreshAutoNormalFooter footerWithRefreshingBlock:^{
        if ([weakSelf.mj_header isRefreshing]) {
            [weakSelf.mj_footer endRefreshing];
            return;
        }
        [weakSelf handlerFooterRefresh];
        if(weakSelf.footerRefreshHandler) weakSelf.footerRefreshHandler();
    }];
    header.lastUpdatedTimeLabel.hidden = true;
    self.mj_header = header;
    [self.mj_footer setHidden:true];
    
    self.tableHeaderView = [UIView new];
    self.tableFooterView = [UIView new];
    
    self.backgroundColor = [UIColor clearColor];
    
    self.mDataItems = [NSMutableArray array];
    self.bHeader = false;
    self.bRefresh = true;
    [self initUI];
    self.mPageNum = 0;
    
    
    self.estimatedRowHeight = 0;
    self.estimatedSectionHeaderHeight = 0;
    self.estimatedSectionFooterHeight = 0;
}

-(void)initUI{
    
}


-(void)setItems:(NSArray *)array alwaysHeaderRefresh:(BOOL)alwaysHeaderRefresh{
    if (self.bHeader && array) {
        if (!alwaysHeaderRefresh) {
            self.bHeader = NO;
        }
        if (self.bOnlyHeaderRefresh || !self.bRefresh) {
            [self.mj_footer setHidden:true];
        }else{
            [self.mj_footer setHidden:(array.count == 0)];
        }        
        [self.mDataItems removeAllObjects];
    }
    [self.mDataItems addObjectsFromArray:array];
    

    if (array.count == 0 && !self.bHeader) { // 不是头部的时候,获取数据为空,底部重设置没有更多数据
        [self.mj_footer endRefreshingWithNoMoreData];
    }else{
        [self stopFooterRefresh];
    }

    [self requestFinish:!alwaysHeaderRefresh];
}


- (void)requestFinish:(BOOL)bFinish
{
    if(bFinish) {
        [self stopHeaderRefresh];
        [self reloadData];
    }
}

#pragma mark - tableviewDelegate
- (NSInteger)numberOfRowsInSection:(NSInteger)section
{
    return 0;
}

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
    return 1;
}

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    [tableView deselectRowAtIndexPath:indexPath animated:YES];
    if(self.didSelectedHandler) self.didSelectedHandler(indexPath);
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    return nil;
}

-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
    return self.mDataItems.count;
}

#pragma mark - emptyDelegate
-(UIImage *)imageForEmptyDataSet:(UIScrollView *)scrollView{
    
    if ([MBANetCheck checkNetAvailable]) {
        return [UIImage imageNamed:@"MBALibFramework.bundle/mba_empty"];
    }else{
        return [UIImage imageNamed:MBAReadImageName(@"WFReloadView.bundle/img_error_reloadView")];
    }
}

-(NSAttributedString *)titleForEmptyDataSet:(UIScrollView *)scrollView{
    if ([MBANetCheck checkNetAvailable]) {
        return [@"数据为空" yb_makeAttributes:^(YBAttributeMake *make) {
            make.yb_font([UIFont systemFontOfSize:MBAReadFloat(UI_COMPONENT_FONT_DEFAULT)]).yb_all();
        }];
    }else{
        return [@"网络异常,请查看网络设置" yb_makeAttributes:^(YBAttributeMake *make) {
            make.yb_font([UIFont systemFontOfSize:MBAReadFloat(UI_COMPONENT_FONT_DEFAULT)]).yb_all();
        }];
    }
}

-(BOOL)emptyDataSetShouldAllowScroll:(UIScrollView *)scrollView{
    return true;
}

- (void)emptyDataSetWillAppear:(UIScrollView *)scrollView {
    // 如果你的空白占位图与需求向左,发生偏移,可如下设置:
    self.contentOffset = CGPointZero;
}

- (void)updateUI
{
    
}

- (void)updateColor
{
    self.separatorColor = MBAReadColor(UI_COMPONENT_LINE_COLOR);
}
- (void)updateLanguage
{
    
}


-(void)handlerHeaderRefresh{
    self.bHeader = true;
    [self.mDataItems removeAllObjects];
    self.mPageNum = 0;
}

-(void)handlerFooterRefresh{
    self.bHeader = false;
    self.mPageNum ++;
}

// header
- (void)startHeaderRefresh{
    [self.mj_header beginRefreshing];
}
- (void)stopHeaderRefresh{
    [self.mj_header endRefreshing];
}


// footer
- (void)startFooterRefresh{
    [self.mj_footer beginRefreshing];
}
- (void)stopFooterRefresh{
    [self.mj_footer endRefreshing];
}

-(void)stopRefresh{
    [self stopHeaderRefresh];
    [self stopFooterRefresh];
}


-(void)setBRefresh:(BOOL)bRefresh{
    _bRefresh = bRefresh;
    [self.mj_header setHidden:!bRefresh];
    [self.mj_footer setHidden:!bRefresh];
}

-(void)setBOnlyHeaderRefresh:(BOOL)bOnlyHeaderRefresh{
    _bOnlyHeaderRefresh = bOnlyHeaderRefresh;
    [self.mj_header setHidden:!bOnlyHeaderRefresh];
    [self.mj_footer setHidden:bOnlyHeaderRefresh];
}

-(void)setBOnlyFooterRefresh:(BOOL)bOnlyFooterRefresh{
    _bOnlyFooterRefresh = bOnlyFooterRefresh;
    [self.mj_header setHidden:bOnlyFooterRefresh];
    [self.mj_footer setHidden:!bOnlyFooterRefresh];
}


@end

  1. webView网页图片离线缓存实现

很多时候我们需要webView离线缓存一些数据,如图片等.

这时就需要NSURLProtocol来实现这功能.
虽然它是一个协议,但是它其实是一个类,而且继承自NSObject。它的作用是处理特定URL协议的加载。它本身是一个抽象类,提供了使用特性URL方案处理URL的基础结构。你可以自己创建NSURLProtocol的子类,来让自己的应用支持自定义的协议或者URL方案。

应用程序永远不需要直接实例化一个NSURLProtocol子类。当一个下载开始的时候,系统创建一个合适的protoco对象来响应URL请求。你要做的就是自己定义一个你自己的protocol,然后在APP启动的时候调用registerClass:,让系统知道你的协议。

UIWebView的离线缓存处理

首先,我们需要自定义一个NSURLProtocol的子类,并且在AppDelegate.m的

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    [NSURLProtocol registerClass:[ZGURLProtocol MBAWebviewImageProtocol]];
    return YES;
}

当URL Load System开始加载一个请求的时候,每个注册的协议类都被依次去调用,以确定是否可以用指定的请求去初始化它。首先被调用的方法是:

+ (BOOL)canInitWithRequest:(NSURLRequest *)request;

在该方法里面进行缓存过滤,如缓存图片,就需要判断路径是否是图片,如果是图片就返回true.

if ([self isImageRequest:path]){
    return ture;
}else{
    return false;
}

如果返回ture,那么就相当于该请求被自定义的URLProtocol来处理。

然后我们在startLoading方法进行缓存处理操作,demo里面有[SDWebImageDownloader sharedDownloader]进行了下载缓存.然后一些业务处理

最后就是一些代码方法:(直接回调即可)

#pragma mark - NSURLConnectionDelegate

- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
    [self.client URLProtocol:self didReceiveResponse:response cacheStoragePolicy:NSURLCacheStorageNotAllowed];
}

- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
    [self.client URLProtocol:self didLoadData:data];
}

- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
    [self.client URLProtocolDidFinishLoading:self];
}

- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
    [self.client URLProtocol:self didFailWithError:error];
}

MBAWebviewImageProtocol文件

MBAWebviewImageProtocol.h
#import <Foundation/Foundation.h>

@interface MBAWebviewImageProtocol : NSURLProtocol

@end
MBAWebviewImageProtocol.m
static NSString *const WebviewImageProtocolHandledKey = @"WebviewImageProtocolHandledKey";

@interface MBAWebviewImageProtocol () <NSURLConnectionDataDelegate>

@property(nonatomic, strong) NSURLConnection *connection;

@end

@implementation MBAWebviewImageProtocol

+ (BOOL)canInitWithRequest:(NSURLRequest *)request {
    NSString *path = request.URL.path;
    if ([self isImageRequest:path]) {
        if ([NSURLProtocol propertyForKey:WebviewImageProtocolHandledKey inRequest:request]) {
            return NO;
        }
        return YES;
    }
    return NO;
}

+ (NSURLRequest *)canonicalRequestForRequest:(NSURLRequest *)request {
    return request;
}


- (void)startLoading {
    NSString *urlString = self.request.URL.absoluteString;
    NSRange range = [urlString rangeOfString:@"?"];
    if(range.location!=NSNotFound){
        urlString = [urlString substringToIndex:range.location];
        [self handlerCacheImage:urlString];
        return;
    }
    
    if ([MBAImageLoadManager readImageLoad] == ImageLoadNO || ([MBAImageLoadManager readImageLoad] == ImageLoadOnlyWifi && [MBANetCheck isEnable3G])) {//.不加载处理
        NSString *pathResource = nil;
        if ([self isTitleIconImg:urlString]) {
            if ([MBAThemeManager readThemeStyle] == ThemeStyleDay) {
                pathResource = @"mba-module-detailsweb.bundle/btn_show_contents_normal.png";
            }else{
                pathResource = @"mba-module-detailsweb.bundle/btn_show_contents_pressed.png";
            }
            NSData *imgUnloadData = [NSData dataWithContentsOfFile:[[NSBundle mainBundle] pathForResource:pathResource ofType:nil]];
            [self myResponseImageData:imgUnloadData];
        }else{
            NSData *imageData = (NSData *)[[CacheManager manager]objectForKey:urlString group:@"image"] ;
            if (imageData) {
                [self myResponseImageData:imageData];
            }else{
                pathResource = @"mba-module-common.bundle/img_unload_replace.png";
                NSData *imgUnloadData = [NSData dataWithContentsOfFile:[[NSBundle mainBundle] pathForResource:pathResource ofType:nil]];
                [self myResponseImageData:imgUnloadData];
            }
        }
        
    } else{
        [self handlerCacheImage:urlString];
    }
}

-(void)handlerCacheImage:(NSString *)urlString{
    NSData *imageData = (NSData *)[[CacheManager manager]objectForKey:urlString group:@"image"] ;
    
    if (imageData) {
        [self myResponseImageData:imageData];
    } else {
        [[SDWebImageDownloader sharedDownloader]downloadImageWithURL:self.request.URL options:SDWebImageDownloaderUseNSURLCache progress:nil completed:^(UIImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, BOOL finished) {
            [self myResponseImageData:data];
            [[CacheManager manager]setObject:data forKey:urlString group:@"image"];
        }];
    }
}


-(void)myResponseImageData:(NSData *)data{
    NSString *mimeType = @"image/jpeg";
    NSMutableDictionary *header = [[NSMutableDictionary alloc] initWithCapacity:2];
    NSString *contentType = [mimeType stringByAppendingString:@";charset=UTF-8"];
    header[@"Content-Type"] = contentType;
    header[@"Content-Length"] = [NSString stringWithFormat:@"%lu", (unsigned long) data.length];
    
    NSHTTPURLResponse *httpResponse = [[NSHTTPURLResponse alloc] initWithURL:self.request.URL
                                                                  statusCode:200
                                                                 HTTPVersion:@"1.1"
                                                                headerFields:header];
    
    [self.client URLProtocol:self didReceiveResponse:httpResponse cacheStoragePolicy:NSURLCacheStorageNotAllowed];
    [self.client URLProtocol:self didLoadData:data];
    [self.client URLProtocolDidFinishLoading:self];
}

- (void)stopLoading {
    [self.connection cancel];
}

//private
+ (BOOL)isImageRequest:(NSString *)URLString
{
    return [UrlUtils isImage:URLString];
}

- (BOOL)isTitleIconImg:(NSString *) URLString {
    
    NSRange columnImgRange = [URLString rangeOfString:@"columntitel-ico.png"];
    NSRange ngColumnImgRange = [URLString rangeOfString:@"columntitel-ng-ico.png"];
    if(columnImgRange.length > 0 || ngColumnImgRange.length > 0) {
        return YES;
    }
    return NO;
}

#pragma mark - NSURLConnectionDelegate

- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
    [self.client URLProtocol:self didReceiveResponse:response cacheStoragePolicy:NSURLCacheStorageNotAllowed];
}

- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
    [self.client URLProtocol:self didLoadData:data];
}

- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
    [self.client URLProtocolDidFinishLoading:self];
}

- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
    [self.client URLProtocol:self didFailWithError:error];
}

相关文章

  • 2017.11tableview 封装 与 webview 缓存

    技术点两点: tableview 封装 与 webview 缓存实现 刷新tableview封装:MBARefre...

  • 带进度条的WebView

    自己封装的一个带进度条的WebView,在此分享一下 WebView添加自定义进度条;实现缓存,有网取网络数据,无...

  • 2018-03-11

    WebView缓存 Android WebView缓存可以分为页面缓存和数据缓存页面缓存是指加载一个网页时htm...

  • 通用代码

    AsyncTask返回封装与数据缓存

  • 与WebView交互JsBridge框架

    与WebView交互(JsBridge框架)一、未封装的JS-Native调用安卓提供Webview用来加载htm...

  • iOS原生UIWebView与JS 交互封装

    公司项目大量使用 WebView,交互相当频繁,基于所以对WebView与 JS 的交互做了些封装 SFWebVi...

  • 混合开发应用调试

    native有用来渲染网页的控件,android被封装为名为webView 。 以webView为例阐述与浏览器区...

  • APP开发实战137-WebView功能设计

    36.9 WebView功能设计 在使用WebView控件时,除了设置是否支持js、缓存大小、缓存模式、文字编码类...

  • Android WebView的使用

    WebView初始化设置 设置缓存路径 设置UserAgent WebView加载url WebView加载首页u...

  • react native 原生UI组件

    原生UI组件的封装方法与封装原生模块十分类似。 我们以 WebView 为例进行封装。 需要继承 SimpleVi...

网友评论

      本文标题:2017.11tableview 封装 与 webview 缓存

      本文链接:https://www.haomeiwen.com/subject/risfbxtx.html