美文网首页iOS 知识点iOS入门
04.项目实战 百思不得姐 登录界面补充,我的界面,设置界面清除

04.项目实战 百思不得姐 登录界面补充,我的界面,设置界面清除

作者: Liwx | 来源:发表于2016-01-25 00:53 被阅读1060次

    @(iOS 项目实战)[项目实战]


    目录

    • 04.项目实战-04 百思不得姐 登录界面补充,我的界面,设置界面清除缓存
      • 补充
      • 约束和frame并用问题
      • 多个对象拥有同样功能,抽取基类
      • 代理注意点
    • 1.登录/注册界面细节
      • 设置UITextField的光标颜色
      • 设置UITextField的占位文字颜色
      • 自定义文本框类实现修改文本框占位文字颜色和光标颜色
      • 设置文本框占位文字颜色方式一
      • 设置文本框占位文字颜色方式二
      • 设置文本框占位文字颜色方式三
    • 2.我的界面搭建
      • storyboard搭建我的界面(静态cell)
      • 我的界面底部板块界面
      • 加载我板块cell网络数据
    • 3.展示网页的几种实现方法
      • SFSafariViewController实现浏览展示网页(iOS9之后才能使用)
      • WKWebView实现展示网页(iOS8之后才能使用)
    • 4.设置界面
      • 获取SDWebImage缓存大小
      • 封装计算文件夹大小/移除文件夹所有文件业务类WXFileCacheManager
      • 获取缓存大小原理(获取文件夹下所有文件的大小)
      • 移除文件夹下所有文件

    补充

    约束和frame并用问题

    只要修改了约束,就修改约束,如果使用frame,就直接修改frame.如果既用约束,又用frame,有可能会造成冲突.

    多个对象拥有同样功能,抽取基类

    如果很多对象都有同样的功能,可以考虑抽取基类

    代理注意点

    不要自己成为自己的代理,之后如果外部重新设置代理,会导致自己的代理功能失效.


    1.登录/注册界面细节

    设置UITextField的光标颜色

    • UITextField的焦点光标颜色

    设置UITextField的主题颜色tintColor属性,将tintColor属性设置成白色,光标颜色就为白色.

    设置UITextField的占位文字颜色

    占位文字实现分析: 占位文字颜色在文本框开始编辑的时候变成白色,结束编辑的时候恢复原来的颜色.设置文本框占位文字颜色项目中多处会使用到,避免多处都要进行重复性设置,建议使用自定义TextField类,将设置占位文字颜色的功能封装到自定义TextField类中.

    自定义文本框类实现修改文本框占位文字颜色和光标颜色

    • 1.自定义文本框类WXTextField
    • 2.在WXTextField类的awakeFormNib方法中设置tintColor属性(只需设置一次),实现设置光标颜色.
      self.tintColor = [UIColor whiteColor];
    • 3.监听文本框开始/结束编辑(开始编辑占位文字颜色为白色,结束编辑占位文字颜色为灰色)
      • 此项目使用Target方式监听文本框开始/结束编辑事件.

    分析几种监听文本框的方式
    - 监听文本框开始/结束编辑方式: 代理,通知,Target三种方式.
    - 代理方式: 使用代理设置控件内部属性,如果外部重新设置了代理,会导致控件内部通过代理设置的功能失效.此场景不适合用代理方式监听.
    - 通知方式: 使用通知的方式监听文本框开始/结束编辑.开始编辑(UITextFieldTextDidBeginEditingNotification)通知,结束编辑(UITextFieldTextDidEndEditingNotification)通知,文本改变(UITextFieldTextDidChangeNotification)通知.此场景也可以使用通知的方式监听.
    - Target方式: 使用Target方式监听文本框开始/结束编辑.监听文本框的开始编辑事件UIControlEventEditingDidBegin结束编辑事件UIControlEventEditingDidEnd.此场景可以使用Target方式监听.

    • 使用Target方式实现参考源码
    // ----------------------------------------------------------------------------
    // 在awakeFromNib方法中设置文本框光标颜色和占位文字字体颜色
    - (void)awakeFromNib
    {
        // 1.设置光标颜色
        self.tintColor = [UIColor whiteColor];
        
        // 2.添加监听文本框开始编辑和结束编辑
        [self addTarget:self action:@selector(textBegin) forControlEvents:UIControlEventEditingDidBegin];
        [self addTarget:self action:@selector(textEnd) forControlEvents:UIControlEventEditingDidEnd];
        
        // 3.设置默认占位文字颜色为灰色
        // 此处需设置占位文字颜色.
    }
    
    #pragma =======================================================================
    #pragma mark - 监听文本框事件
    // ----------------------------------------------------------------------------
    // 监听到文本框开始编辑
    - (void)textBegin
    {
        // 设置开始编辑时占位文字的颜色
    }
    
    // ----------------------------------------------------------------------------
    // 监听到文本框结束编辑调用
    - (void)textEnd
    {
        // 设置结束编辑时占位文字的颜色
    }
    
    • 4.设置占位文字颜色

    设置占位文字的场景: 默认情况的占位文字颜色,开始编辑时修改占位文字颜色,结束编辑时恢复占位文字颜色.

    设置占位文字颜色分析
    - 方式一: 通过修改UITextField的attributedPlaceholder属性.
    - 方法二: 使用KVC方式获取占位文字的UILabel,获取到Label在设置Label的文字颜色.该方法有前提,必须在设置占位文字颜色前先设置占位文字,因为占位文本Label是使用懒加载,如果使用KVC方式获取占位文本Label时,有可能该Label还没创建,所以使用该方法必须确保占位文本Label已经创建.
    - 方式三: 使用RunTime方式,通过分类实现设置文本框的占位文字颜色.


    设置文本框占位文字颜色方式一
    • 修改UITextField的attributedPlaceholder属性
    // ----------------------------------------------------------------------------
    // TODO: TextField 设置文本框的占位文字颜色 方法一: 通过修改UITextField的attributedPlaceholder属性
    // 在自定义TextField类中使用UITextField的attributedPlaceholder属性修改
    - (void)setAttrPlaceholderColor:(UIColor *)placeholderColor
    {
        // 1.设置富文本属性
        NSMutableDictionary *attrDict = [NSMutableDictionary dictionary];
        attrDict[NSForegroundColorAttributeName] = placeholderColor;
        
        // 2.创建富文本属性,并设置颜色
        NSAttributedString *attributedString = [[NSAttributedString alloc] initWithString:self.placeholder attributes:attrDict];
        
        // 3.将富文本赋值给UITextField的attributedPlaceholder属性
        self.attributedPlaceholder = attributedString;
    }
    

    设置文本框占位文字颜色方式二
    • 断点调试获取到私有成员_placeholderLabel属性名


      断点调试获取私有成员_placeholderLabel属性名.png

    • 使用KVC方式获取UITextField私有属性_placeholderLabel(占位文字Label),获取到Label在设置Label的文字颜色

    注意: OC系统自带控件中,所有的子控件都是懒加载.该方法有前提,必须在设置占位文字颜色前先设置占位文字,因为占位文本Label是使用懒加载,如果使用KVC方式获取占位文本Label时,有可能该Label还没创建,所以使用该方法必须确保占位文本Label已经创建.

    // ----------------------------------------------------------------------------
    // TODO: TextField 设置文本框的占位文字颜色 方法二: 使用KVC方式获取占位文字的UILabel,获取到Label在设置Label的文字颜色.
    - (void)setKVCPlaceholderColor:(UIColor *)placeholderColor
    {
        // 1.使用KVC获取文本框中的占位文字Label
        UILabel *placeholderLabel = [self valueForKeyPath:@"placeholderLabel"];
        
        // 2.设置占位文字Label的颜色
        placeholderLabel.textColor = placeholderColor;
    }
    

    设置文本框占位文字颜色方式三
    • 使用RunTime方式,通过分类设置文本框的占位文字颜色

    实现思路分析: 1.先保存占位文字颜色到系统类动态添加的属性. 2.取出动态添加的placeholderColor给系统的占位文字Label设置字体颜色

    • 1.创建UITextField+Placeholder分类

    • 2.使用动态添加placeholderColor属性,用于存放占位文字的颜色.

      • 在UITextField+Placeholder.h中声明@property UIColor *placeholderColor;,相当于是声明set,get方法.
      • 实现placeholderColor的set,get方法
        set方法中关联动态添加的属性,使用objc_setAssociatedObject函数关联动态添加的属性.
        使用KVC方式获取文本框的占位文字的UILabel,并给占位文字的Label设置文本颜色.
        get方法中通过objc_getAssociatedObject函数获取关联的对象
    • 3.给系统的设置占位文字的setPlaceholder:方法添加功能.

      • 自定义实现wx_setPlaceholder:方法,该方法实现给系统的setPlaceholder:方法添加设置占位文本颜色的功能.
    • 4.交换系统方法: 在load类方法中实现自定义方法和系统方法交换.

      • 注意: 自定义的wx_setPlaceholder:方法系统的setPlaceholder:方法交换,注意别写错要交换的系统方法的setPlaceholder:方法.

    • RunTime方式实现设置文本框占位文字颜色参考代码
    // ----------------------------------------------------------------------------
    // TODO: TextField 方式三: 使用RunTime方式,通过分类设置文本框的占位文字颜色
    
    // ----------------------------------------------------------------------------
    // UITextField+PlaceholderColor.h文件
    #import <UIKit/UIKit.h>
    
    @interface UITextField (Placeholder)
    
    /** 动态添加placeholderColor属性 */
    @property UIColor *placeholderColor;
    
    @end
    
    // ----------------------------------------------------------------------------
    // UITextField+PlaceholderColor.m文件
    #import "UITextField+Placeholder.h"
    #import <objc/message.h>
    
    @implementation UITextField (PlaceholderColor)
    
    #pragma =======================================================================
    #pragma mark - RunTime实现交换方法
    
    // ----------------------------------------------------------------------------
    // 在load类方法中(类加载进内存的时候调用,只调用一次)
    + (void)load
    {
        // 1.获取要交互的方法 Method是C语言结构体,不需要加*
        Method setPlaceholderMethod = class_getInstanceMethod(self, @selector(setPlaceholder:));
        Method wx_setPlaceholderMethod = class_getInstanceMethod(self, @selector(wx_setPlaceholder:));
        
        // 2.交换方法
        method_exchangeImplementations(setPlaceholderMethod, wx_setPlaceholderMethod);
    }
    
    // ----------------------------------------------------------------------------
    // 给系统的方法添加设置占位文本颜色的功能
    - (void)wx_setPlaceholder:(NSString *)placeholder
    {
        // 1.调用交互方法,实际是调用setPlaceholderColor:方法
        [self wx_setPlaceholder:placeholder];
        
        // 2.设置保存的占位文字颜色
        self.placeholderColor = self.placeholderColor;
    }
    
    #pragma =======================================================================
    #pragma mark - 使用RunTime实现关联动态添加的属性placeholderColor
    // ----------------------------------------------------------------------------
    // 重写set方法设置占位文本颜色
    - (void)setPlaceholderColor:(UIColor *)placeholderColor
    {
        // 1.关联动态placeholderColor添加的属性,保存占位文字颜色到系统类动态添加的placeholderColor属性
        
        // object:保存到哪个对象中
        // key:属性名
        // value:属性值
        // policy:策略
        objc_setAssociatedObject(self, @"placeholderColor", placeholderColor, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
        
        // 2.使用KVC获取占位文字的Label,并设置占位文字Label的字体颜色
        UILabel *placeholderLabel = [self valueForKeyPath:@"placeholderLabel"];
        placeholderLabel.textColor = placeholderColor;
    }
    
    // ----------------------------------------------------------------------------
    // 重写get方法获取placeholderColor关联的对象
    - (UIColor *)placeholderColor
    {
        return objc_getAssociatedObject(self, @"placeholderColor");
    }
    @end
    

    2.我的界面搭建

    • 我的界面分析


      我的界面分析.png

    只有storyboard才能设置静态单元格(静态cell),xib不能设置静态单元格.


    storyboard搭建我的界面(静态cell)

    • 1.使用storyboard设置好静态单元格

      • 需设置storyboard中控制器的管理类.
        设置storyboard中控制器的管理类.png
      • 删除系统自动生成的tableView数据源方法代码.
    • 2.storyboard必须通过代码加载

      • 方式一: 加载箭头指向的控制器instantiateInitialViewController方法.
      // 在WXTabBarController.m中,添加子控制器的方法中
      // TODO: Storyboard加载控制器,storyboard必须手动加载控制器
      UIStoryboard *storyboard = [UIStoryboard storyboardWithName:NSStringFromClass([WXMeViewController class]) bundle:nil];
      WXMeViewController *meVc = [storyboard instantiateInitialViewController];
      
      • 方式二: 加载指定标识的控制器instantiateViewControllerWithIdentifier:方法.(在storyboard中必须设置StoryboardID)

    我的界面底部板块界面

    • UICollectionView的基本使用

      • 初始化时必须指定布局
        • 通过布局类设置cell的尺寸.
        • 使用布局设置最小行列间距,滚动方法等.
      • 必须注册cell
      • 必须自定义cell
    • tableView的注意点

      • 添加到tableView的footView的子控件不需要设置位置尺寸.

    • 1.设置底部tableFooterView为UICollectionView
    
    // ----------------------------------------------------------------------------
    // 常量和宏
    static NSString * const ID = @"cell";
    static NSInteger const colCount = 4;
    static CGFloat const margin = 1;
    #define cellWH ((screenW - margin * (colCount - 1)) / colCount)
    
    // ----------------------------------------------------------------------------
    // 设置底部tableFooterView
    - (void)setupTableFooterView
    {
        // ------------------------------------------------------------------------
        // 1.创建流水布局,设置cell的尺寸和行列最小间距
        UICollectionViewFlowLayout *flowLayout = [[UICollectionViewFlowLayout alloc] init];
        flowLayout.itemSize = CGSizeMake(cellWH, cellWH);
        flowLayout.minimumLineSpacing = margin;
        flowLayout.minimumInteritemSpacing = margin;
        
        // ------------------------------------------------------------------------
        // 2.创建collectionView,设置collectionView的属性
        UICollectionView *collectionView = [[UICollectionView alloc] initWithFrame:CGRectMake(0, 0, 0, 0) collectionViewLayout:flowLayout];
        collectionView.backgroundColor = WXColor(206, 206, 206);
        collectionView.scrollEnabled = NO;
        self.collectionView = collectionView;
        
        // ------------------------------------------------------------------------
        // 3.设置collectionView的数据源和代理
        collectionView.dataSource = self;
        collectionView.delegate = self;
        self.tableView.tableFooterView = collectionView;
        
        // ------------------------------------------------------------------------
        // 4.注册cell
        [collectionView registerNib:[UINib nibWithNibName:NSStringFromClass([WXSquareCell class]) bundle:nil] forCellWithReuseIdentifier:ID];
    }
    

    • 2.设置tableView的分组间距
      • 分组间距调整


        分组间距调整.png

    • 3.调整tableView分组间距

      • 最上面间距不属于组头部间距
      • 调整组尾部间距
      • 经过分析,顶部的间距是第一个cell的y值为35,设置内边距左边距为-25,这样就能实现设置最顶部的间距为10;
      • 实现参考代码
        // ----------------------------------------------------------------------------
        // 设置tableView的分组间距
        - (void)setSectionMargin
        {
            // 设置tableView的分组间距(调整分组的头部尾部间距), 最顶部高度为35,通过设置内边距将最顶部间距设置为10
            self.tableView.sectionFooterHeight = 10;
            self.tableView.sectionHeaderHeight = 0;
            self.tableView.contentInset = UIEdgeInsetsMake(-25, 0, 0, 0);
        }
      

    加载我板块cell网络数据

    • 1.使用AFN加载板块cell网络数据

      • 1.创建请求会话管理者
      • 2.拼接请求参数(必选参数一定要写)
      • 3.发送请求

      • 请求板块cell数据参考代码
        // ----------------------------------------------------------------------------
        // 请求cell网络数据
        - (void)loadData
        {
            // 1.创建请求会话管理者
            AFHTTPSessionManager *mgr = [AFHTTPSessionManager manager];
            
            // 2.拼接请求参数
            NSMutableDictionary *parameters = [NSMutableDictionary dictionary];
            parameters[@"a"] = @"square";
            parameters[@"c"] = @"topic";
            
            // 3.发送请求
            [mgr GET:baseUrl parameters:parameters progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
                
                // 3.1 字典数组转模型数组
                self.squareList = [WXSquareItem mj_objectArrayWithKeyValuesArray:responseObject[@"square_list"]];
                
                // 3.2 处理请求的数据
                [self resolveData];
                
                // 3.3 刷新表格
                [self.collectionView reloadData];
                
                // 3.4 计算collectView的高度
                NSInteger count = self.squareList.count;
                // 3.4.1 计算行数
                NSInteger row = (count - 1) / colCount + 1;
                CGFloat collectionViewH = row * cellWH;
                self.collectionView.wx_height = collectionViewH;
                
                
                // TODO: 3.5 重新设置tableFooterView的显示内容,如果重新设置,会导致拖动到最底部cell会自动回弹
                self.tableView.tableFooterView = self.collectionView;
                
            } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
                NSLog(@"%@", error);
            }];
        }
    
    • 2.处理请求的数据

    作用: 主要是用于补齐格子,不然未填充的格子会变成灰色的效果.

    - 处理请求的数据实现代码
    
      // ----------------------------------------------------------------------------
      // 处理请求的数据
      - (void)resolveData
      {
          // 如果数据不是4的倍数,添加到4的倍数.主要是用于补齐格子,不然未填充的格子会变成灰色的效果.
          NSInteger count = self.squareList.count;
          NSInteger extre = count % colCount;
          if (extre) {
              for (NSInteger i = 0; i < colCount - extre ; i++) {
                  WXSquareItem *item = [[WXSquareItem alloc] init];
                  [self.squareList addObject:item];
              }
          }
      }
    

    • 3.使用xib自定义UICollectionViewCell.(WXSquareCell)

      • 使用AutoLayout布局WXSquareCell.(适配不同屏幕)布局视图


        使用AutoLayout布局WXSquareCell.(适配不同屏幕)布局视图.png

      • 设置图片和文字: 提供模型数据,重写set方法
        // ----------------------------------------------------------------------------
        // 重写模型的set方法,设置图片和文字
        - (void)setItem:(WXSquareItem *)item
        {
            _item = item;
            
            [self.iconImageView sd_setImageWithURL:[NSURL URLWithString:item.icon]];
            self.nameLabel.text = item.name;
        }
      
      • 实现点击cell时闪烁效果
        // ----------------------------------------------------------------------------
        // WXSquareCell.m文件
        - (void)awakeFromNib {
            // 设置UICollectionViewCell选中时的背景色
            UIView *backView =  [[UIView alloc] init];
            backView.backgroundColor = WXColor(206, 206, 206);
            self.selectedBackgroundView = backView;
        }
        
        // ----------------------------------------------------------------------------
        // WXMeViewController.m文件
        - (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath
        {
            // 1.处理点击闪烁
            UICollectionViewCell *cell = [collectionView cellForItemAtIndexPath:indexPath];
            cell.selected = YES;
            dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
                cell.selected = NO;
            });
            
            // 点击跳转网页处理
        }
      

    3.展示网页的几种实现方法

    展示网页: 1.WebView 2.openUrl
    - WebView: 没有自带功能.好处: 就在当前应用下展示网页.弊端: webView不能监听进度条.
    - safari: 自带了很多功能,弊端: 必须要跳转到其他应用.


    SFSafariViewController实现浏览展示网页(iOS9之后才能使用)

    • SFSafariViewController实现展示网页实现参考代码
    // 使用SFSafariViewController需导入SafariServices/SafariServices.h头文件
    #import <SafariServices/SafariServices.h>
    // --------------------------------------------------------------------
    // TODO: SFSafariViewController实现浏览展示网页
    // 3.1 创建Safari网页控制器 iOS9才能用
    SFSafariViewController *safariVc = [[SFSafariViewController alloc] initWithURL:[NSURL URLWithString:item.url]];
    safariVc.delegate = self;
    
    // 3.2 跳转网页控制器
    [self presentViewController:safariVc animated:YES completion:nil];
    safariVc.hidesBottomBarWhenPushed = YES;
    [self.navigationController pushViewController:safariVc animated:YES];
    
    • SFSafariViewControllerDelegate代理方法
    #pragma =======================================================================
    #pragma mark - SFSafariViewControllerDelegat代理协议
    
    // ----------------------------------------------------------------------------
    // TODO: SFSafariViewController 监听Safari点击完成按钮
    - (void)safariViewControllerDidFinish:(SFSafariViewController *)controller;
    
    // ----------------------------------------------------------------------------
    // TODO: SFSafariViewController 监听Safari初始化载入完成
    - (void)safariViewController:(SFSafariViewController *)controller didCompleteInitialLoad:(BOOL)didLoadSuccessfully;
    

    WKWebView实现展示网页(iOS8之后才能使用)

    • WebKit框架的WKWebView展示网页(iOS8之后才能使用)

      • 在工程文件中手动导入WebKit框架
        • 使用WKWebView需先导入库WebKit库,否则会报错
          Undefined symbols for architecture x86_64:
          "OBJC_CLASS$_WKWebView", referenced from:
          工程文件中手动导入WebKit框架 .png
      • KVO监听前进后退刷新等属性变化
      • KVO监听加载进度.
      • KVO监听网页标题改变.
    • 自定义WKWebView

      • 1.使用xib布局网页展示界面


        使用xib布局网页展示界面.png
        • 在viewDidLayoutSubviews方法中重写设置WKWebView的尺寸
          // ----------------------------------------------------------------------------
          // 控制器的view子控件布局完成调用
          - (void)viewDidLayoutSubviews
          {
              [super viewDidLayoutSubviews];
              
              // 1.设置wkWebView位置尺寸
              self.wkWebView.frame = self.htmlView.bounds;
          }
      
      • 2.提供一个url,让外界传递要展示的url
      • 3.添加WXWebView到控制器的view,使用WKWebView的loadRequest:方法加载网页
      // 通过传递的参数加载网页
      NSURLRequest *request = [NSURLRequest requestWithURL:self.url];
      [wkWebView loadRequest:request];
      
      • 4.使用KVO添加监听后退,前进,进度条,网页标题的改变
        #pragma =======================================================================
        #pragma mark - 监听后退,前进,进度条,网页标题的监听
        
        // ----------------------------------------------------------------------------
        // 使用KVO添加监听
        - (void)setupAddObserver
        {
            // 1.添加后退,前进,进度条,网页标题的监听
            [self.wkWebView addObserver:self forKeyPath:@"canGoBack" options:NSKeyValueObservingOptionNew context:nil];
            [self.wkWebView addObserver:self forKeyPath:@"canGoForward" options:NSKeyValueObservingOptionNew context:nil];
            [self.wkWebView addObserver:self forKeyPath:@"estimatedProgress" options:NSKeyValueObservingOptionNew context:nil];
            [self.wkWebView addObserver:self forKeyPath:@"title" options:NSKeyValueObservingOptionNew context:nil];
        }
        
        // ----------------------------------------------------------------------------
        // 观察的属性有新值的时候就会调用
        - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context
        {
            // 1.更新后退,前进,进度条,网页标题的监听
            self.backItem.enabled = _wkWebView.canGoBack;
            self.forwardItem.enabled = _wkWebView.canGoForward;
            self.progressView.progress = _wkWebView.estimatedProgress;
            self.progressView.hidden = _wkWebView.estimatedProgress >= 1;
            self.title = _wkWebView.title;
        }
        
        // ----------------------------------------------------------------------------
        // 移除KVO监听, 如果没移除KVO监听,点击返回会报错"NSKeyValueObservationInfo"
        - (void)dealloc
        {
            [self.wkWebView removeObserver:self forKeyPath:@"canGoBack"];
            [self.wkWebView removeObserver:self forKeyPath:@"canGoForward"];
            [self.wkWebView removeObserver:self forKeyPath:@"estimatedProgress"];
            [self.wkWebView removeObserver:self forKeyPath:@"title"];
        }
      
      • 4.点击前进,后退,刷新按钮执行相应操作
        • WKWebView的前进goForward方法,后退goBack方法,刷新reload方法,
        #pragma =======================================================================
        #pragma mark - 监听后退,前进,刷新按钮的点击调用方法
        // ----------------------------------------------------------------------------
        // 后退按钮点击调用
        - (IBAction)back:(UIBarButtonItem *)sender {
            [self.wkWebView goBack];
        }
        
        // ----------------------------------------------------------------------------
        // 前进按钮点击调用
        - (IBAction)forward:(UIBarButtonItem *)sender {
            [self.wkWebView goForward];
        }
        
        // ----------------------------------------------------------------------------
        // 刷新按钮点击调用
        - (IBAction)reload:(UIBarButtonItem *)sender {
            [self.wkWebView reload];
        }
      

    4.设置界面


    获取SDWebImage缓存大小

    • SDWebImage获取的图片存放在Cache/default,获取该目录的缓存大小

      // 获取SDWebImage缓存大小
      NSUInteger cacheSize = [[SDImageCache sharedImageCache] getSize];
      

    封装计算文件夹大小/移除文件夹所有文件业务类WXFileCacheManager

    业务类: 常见业务类有网络请求类,处理文件缓存类.
    业务类命名: 类名可以以manager结尾.


    获取缓存大小原理(获取文件夹下所有文件的大小)

    • 获取文件夹的内容属于比较耗时的操作,最好放在异步子线程处理,避免导致UI操作卡顿.以下所有操作都放在异步子线程中执行.

    • 封装获取文件夹大小的类方法

    • 1.使用[NSFileManager defaultManager];获得文件管理者, NSFileManager是单例.

    • 2.判断路径参数是否存在并且是文件夹

      • 如果路径不存在或不是文件夹, 抛出异常
    • 3.获取文件夹下的所有文件子路径

      • 调用NSFileManager 的对象方法subpathsAtPath:方法获取文件夹下所有文件的子路径
    • 4.遍历文件夹下的所有文件,累计文件夹下的所有文件大小

      • 4.1 拼接全路径
      • 4.2 过滤隐藏文件和文件夹: 判断如果是隐藏文件带有DS字符串,路径不存在或不是文件夹路径,则跳过
      • 4.3 获取文件属性,获取文件大小
        *NSDictionary attr = [mgr attributesOfItemAtPath:fullPath error:nil];
        NSInteger fileSize = [attr[NSFileSize] integerValue];
      • 4.4 累计所有文件大小
    • 5.执行计算完成后要处理的操作.执行block.

    因计算文件夹大小在异步子线程中执行,为了获得异步子线程计算文件夹大小的结果,可以让封装的方法传入一个block参数,让子线程调用block方法,并将计算结果传递给外界.如果block内部有刷新UI操作,必须在主线程调用block.
    异步方法不需要设置返回值.

    - 主线程回调执行block参考代码
    
    ```objectivec
    dispatch_async(dispatch_get_main_queue(), ^{
        if (completeBlock) {
            completeBlock(totalSize);
        }
    });
    ```
    

    • 获取文件夹内所有文件大小参考代码
    // ----------------------------------------------------------------------------
    // TODO: 获取文件夹大小
    + (void)getCacheSizeOfDirectoriesPath:(NSString *)directoriesPath completeBlock:(void(^)(NSInteger))completeBlock
    {
        // ------------------------------------------------------------------------
        // 异步(子线程)计算文件大小,此操作比较耗时,所以放在子线程计算
        dispatch_async(dispatch_get_global_queue(0, 0), ^{
            
            // 1.创建文件管理者
            NSFileManager *mgr = [NSFileManager defaultManager];
            
            // TODO: 2.判断是否是文件夹
            BOOL isDirectory;
            // 返回值: 路径是否存在, isDirectory: 输出是否是文件夹(目录)
            BOOL isExists = [mgr fileExistsAtPath:directoriesPath isDirectory:&isDirectory];
            // 如果路径不存在或不是文件夹, 抛出异常
            if (!isExists || !isDirectory) {
                NSException *exp = [NSException exceptionWithName:@"directoriesPathError" reason:@"directoriesPath must be directory" userInfo:nil];
                [exp raise];
            }
            
            // 3.获取文件夹下的所有文件子路径
            NSArray *subPathArray = [mgr subpathsAtPath:directoriesPath];
            
            // --------------------------------------------------------------------
            // 4.遍历文件夹下的所有文件,累计文件夹下的所有文件大小
            NSInteger totalSize = 0;
            for (NSString *subPath in subPathArray) {
                
                // 4.1 拼接全路径
                NSString *fullPath = [directoriesPath stringByAppendingPathComponent:subPath];
                
                // 4.2 过滤隐藏文件和文件夹: 判断如果是隐藏文件带有DS字符串,路径不存在或不是文件夹路径,则跳过
                isExists = [mgr fileExistsAtPath:fullPath isDirectory:&isDirectory];
                if ([fullPath containsString:@"DS"] || !isExists || isDirectory) {
                    continue;
                }
                
                // 4.3 获取文件属性
                NSDictionary *attr = [mgr attributesOfItemAtPath:fullPath error:nil];
                
                // 4.4 获取文件大小
                NSInteger fileSize = [attr[NSFileSize] integerValue];
                
                // 4.5 累计文件大小
                totalSize += fileSize;
                
            }
            
            // --------------------------------------------------------------------
            // 执行主线程回调,因为block有刷新UI操作,所以必须在主线程执行
            dispatch_async(dispatch_get_main_queue(), ^{
                if (completeBlock) {
                    completeBlock(totalSize);
                }
            });
            
        });
    }
    

    移除文件夹下所有文件

    • 移除文件夹下所有文件的类方法
    • 移除文件夹的内容属于比较耗时的操作,最好放在异步子线程处理,避免导致UI操作卡顿.以下所有操作都放在异步子线程中执行.
    • 1.使用[NSFileManager defaultManager];获得文件管理者, NSFileManager是单例.
    • 2.判断路径参数是否存在并且是文件夹
      • 如果路径不存在或不是文件夹, 抛出异常
    • 3.获取文件夹下的所有文件子路径
      • 调用NSFileManager 的对象方法subpathsAtPath:方法获取文件夹下所有文件的子路径
    • 4.遍历文件夹下的所有文件,累计文件夹下的所有文件大小
      • 4.1 拼接全路径
      • 4.2 移除文件
    • 5.执行移除文件完成后要处理的操作.执行block.

    • 移除文件夹下所有文件实现参考代码
    // ----------------------------------------------------------------------------
    // TODO: 移除文件夹路径下的所有文件
    + (void)removeDirectoriesPath:(NSString *)directoriesPath completeBlock:(void(^)())completeBlock
    {
        // ------------------------------------------------------------------------
        // 异步(子线程)移除,此操作比较耗时,所以放在子线程执行
        dispatch_async(dispatch_get_global_queue(0, 0), ^{
            
            // 1.创建文件管理者
            NSFileManager *mgr = [NSFileManager defaultManager];
            
            // 2.判断是否是文件夹
            BOOL isDirectory;
            BOOL isExists = [mgr fileExistsAtPath:directoriesPath isDirectory:&isDirectory];
            if (!isExists || !isDirectory) {
                NSException *exp = [NSException exceptionWithName:@"directoriesPathError" reason:@"directoriesPath must be directory" userInfo:nil];
                [exp raise];
            }
            
            // 3.获取路径下所有子路径
            NSArray *subPathArray = [mgr subpathsAtPath:directoriesPath];
            
            // 4.遍历移除文件夹下的所有文件
            for (NSString *subPath in subPathArray) {
                // 4.1 拼接全路径
                NSString *fullPath = [directoriesPath stringByAppendingPathComponent:subPath];
                
                // 4.2 移除文件
                [mgr removeItemAtPath:fullPath error:nil];
            }
            
            // 5.执行移除文件完成后要处理的操作.避免block里有执行UI操作,最好在主线程下执行
            dispatch_async(dispatch_get_main_queue(), ^{
                if (completeBlock) {
                    completeBlock();
                }
            });
        });
    }
    

    相关文章

      网友评论

        本文标题:04.项目实战 百思不得姐 登录界面补充,我的界面,设置界面清除

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