04.項(xiàng)目實(shí)戰(zhàn) 百思不得姐 登錄界面補(bǔ)充,我的界面,設(shè)置界面清除緩存

@(iOS 項(xiàng)目實(shí)戰(zhàn))[項(xiàng)目實(shí)戰(zhàn)]


目錄

  • 04.項(xiàng)目實(shí)戰(zhàn)-04 百思不得姐 登錄界面補(bǔ)充,我的界面,設(shè)置界面清除緩存
    • 補(bǔ)充
    • 約束和frame并用問題
    • 多個(gè)對(duì)象擁有同樣功能,抽取基類
    • 代理注意點(diǎn)
  • 1.登錄/注冊(cè)界面細(xì)節(jié)
    • 設(shè)置UITextField的光標(biāo)顏色
    • 設(shè)置UITextField的占位文字顏色
    • 自定義文本框類實(shí)現(xiàn)修改文本框占位文字顏色和光標(biāo)顏色
    • 設(shè)置文本框占位文字顏色方式一
    • 設(shè)置文本框占位文字顏色方式二
    • 設(shè)置文本框占位文字顏色方式三
  • 2.我的界面搭建
    • storyboard搭建我的界面(靜態(tài)cell)
    • 我的界面底部板塊界面
    • 加載我板塊cell網(wǎng)絡(luò)數(shù)據(jù)
  • 3.展示網(wǎng)頁的幾種實(shí)現(xiàn)方法
    • SFSafariViewController實(shí)現(xiàn)瀏覽展示網(wǎng)頁(iOS9之后才能使用)
    • WKWebView實(shí)現(xiàn)展示網(wǎng)頁(iOS8之后才能使用)
  • 4.設(shè)置界面
    • 獲取SDWebImage緩存大小
    • 封裝計(jì)算文件夾大小/移除文件夾所有文件業(yè)務(wù)類WXFileCacheManager
    • 獲取緩存大小原理(獲取文件夾下所有文件的大小)
    • 移除文件夾下所有文件

補(bǔ)充

約束和frame并用問題

只要修改了約束,就修改約束,如果使用frame,就直接修改frame.如果既用約束,又用frame,有可能會(huì)造成沖突.

多個(gè)對(duì)象擁有同樣功能,抽取基類

如果很多對(duì)象都有同樣的功能,可以考慮抽取基類

代理注意點(diǎn)

不要自己成為自己的代理,之后如果外部重新設(shè)置代理,會(huì)導(dǎo)致自己的代理功能失效.


1.登錄/注冊(cè)界面細(xì)節(jié)

設(shè)置UITextField的光標(biāo)顏色

  • UITextField的焦點(diǎn)光標(biāo)顏色

設(shè)置UITextField的主題顏色tintColor屬性,將tintColor屬性設(shè)置成白色,光標(biāo)顏色就為白色.

設(shè)置UITextField的占位文字顏色

占位文字實(shí)現(xiàn)分析: 占位文字顏色在文本框開始編輯的時(shí)候變成白色,結(jié)束編輯的時(shí)候恢復(fù)原來的顏色.設(shè)置文本框占位文字顏色項(xiàng)目中多處會(huì)使用到,避免多處都要進(jìn)行重復(fù)性設(shè)置,建議使用自定義TextField類,將設(shè)置占位文字顏色的功能封裝到自定義TextField類中.

自定義文本框類實(shí)現(xiàn)修改文本框占位文字顏色和光標(biāo)顏色

  • 1.自定義文本框類WXTextField
  • 2.在WXTextField類的awakeFormNib方法中設(shè)置tintColor屬性(只需設(shè)置一次),實(shí)現(xiàn)設(shè)置光標(biāo)顏色.
    self.tintColor = [UIColor whiteColor];
  • 3.監(jiān)聽文本框開始/結(jié)束編輯(開始編輯占位文字顏色為白色,結(jié)束編輯占位文字顏色為灰色)
    • 此項(xiàng)目使用Target方式監(jiān)聽文本框開始/結(jié)束編輯事件.

分析幾種監(jiān)聽文本框的方式
- 監(jiān)聽文本框開始/結(jié)束編輯方式: 代理,通知,Target三種方式.
- 代理方式: 使用代理設(shè)置控件內(nèi)部屬性,如果外部重新設(shè)置了代理,會(huì)導(dǎo)致控件內(nèi)部通過代理設(shè)置的功能失效.此場(chǎng)景不適合用代理方式監(jiān)聽.
- 通知方式: 使用通知的方式監(jiān)聽文本框開始/結(jié)束編輯.開始編輯(UITextFieldTextDidBeginEditingNotification)通知,結(jié)束編輯(UITextFieldTextDidEndEditingNotification)通知,文本改變(UITextFieldTextDidChangeNotification)通知.此場(chǎng)景也可以使用通知的方式監(jiān)聽.
- Target方式: 使用Target方式監(jiān)聽文本框開始/結(jié)束編輯.監(jiān)聽文本框的開始編輯事件UIControlEventEditingDidBegin結(jié)束編輯事件UIControlEventEditingDidEnd.此場(chǎng)景可以使用Target方式監(jiān)聽.

  • 使用Target方式實(shí)現(xiàn)參考源碼
// ----------------------------------------------------------------------------
// 在awakeFromNib方法中設(shè)置文本框光標(biāo)顏色和占位文字字體顏色
- (void)awakeFromNib
{
    // 1.設(shè)置光標(biāo)顏色
    self.tintColor = [UIColor whiteColor];
    
    // 2.添加監(jiān)聽文本框開始編輯和結(jié)束編輯
    [self addTarget:self action:@selector(textBegin) forControlEvents:UIControlEventEditingDidBegin];
    [self addTarget:self action:@selector(textEnd) forControlEvents:UIControlEventEditingDidEnd];
    
    // 3.設(shè)置默認(rèn)占位文字顏色為灰色
    // 此處需設(shè)置占位文字顏色.
}

#pragma =======================================================================
#pragma mark - 監(jiān)聽文本框事件
// ----------------------------------------------------------------------------
// 監(jiān)聽到文本框開始編輯
- (void)textBegin
{
    // 設(shè)置開始編輯時(shí)占位文字的顏色
}

// ----------------------------------------------------------------------------
// 監(jiān)聽到文本框結(jié)束編輯調(diào)用
- (void)textEnd
{
    // 設(shè)置結(jié)束編輯時(shí)占位文字的顏色
}
  • 4.設(shè)置占位文字顏色

設(shè)置占位文字的場(chǎng)景: 默認(rèn)情況的占位文字顏色,開始編輯時(shí)修改占位文字顏色,結(jié)束編輯時(shí)恢復(fù)占位文字顏色.

設(shè)置占位文字顏色分析
- 方式一: 通過修改UITextField的attributedPlaceholder屬性.
- 方法二: 使用KVC方式獲取占位文字的UILabel,獲取到Label在設(shè)置Label的文字顏色.該方法有前提,必須在設(shè)置占位文字顏色前先設(shè)置占位文字,因?yàn)檎嘉晃谋綥abel是使用懶加載,如果使用KVC方式獲取占位文本Label時(shí),有可能該Label還沒創(chuàng)建,所以使用該方法必須確保占位文本Label已經(jīng)創(chuàng)建.
- 方式三: 使用RunTime方式,通過分類實(shí)現(xiàn)設(shè)置文本框的占位文字顏色.


設(shè)置文本框占位文字顏色方式一
  • 修改UITextField的attributedPlaceholder屬性
// ----------------------------------------------------------------------------
// TODO: TextField 設(shè)置文本框的占位文字顏色 方法一: 通過修改UITextField的attributedPlaceholder屬性
// 在自定義TextField類中使用UITextField的attributedPlaceholder屬性修改
- (void)setAttrPlaceholderColor:(UIColor *)placeholderColor
{
    // 1.設(shè)置富文本屬性
    NSMutableDictionary *attrDict = [NSMutableDictionary dictionary];
    attrDict[NSForegroundColorAttributeName] = placeholderColor;
    
    // 2.創(chuàng)建富文本屬性,并設(shè)置顏色
    NSAttributedString *attributedString = [[NSAttributedString alloc] initWithString:self.placeholder attributes:attrDict];
    
    // 3.將富文本賦值給UITextField的attributedPlaceholder屬性
    self.attributedPlaceholder = attributedString;
}

設(shè)置文本框占位文字顏色方式二
  • 斷點(diǎn)調(diào)試獲取到私有成員_placeholderLabel屬性名


    斷點(diǎn)調(diào)試獲取私有成員_placeholderLabel屬性名.png

  • 使用KVC方式獲取UITextField私有屬性_placeholderLabel(占位文字Label),獲取到Label在設(shè)置Label的文字顏色

注意: OC系統(tǒng)自帶控件中,所有的子控件都是懶加載.該方法有前提,必須在設(shè)置占位文字顏色前先設(shè)置占位文字,因?yàn)檎嘉晃谋綥abel是使用懶加載,如果使用KVC方式獲取占位文本Label時(shí),有可能該Label還沒創(chuàng)建,所以使用該方法必須確保占位文本Label已經(jīng)創(chuàng)建.

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

設(shè)置文本框占位文字顏色方式三
  • 使用RunTime方式,通過分類設(shè)置文本框的占位文字顏色

實(shí)現(xiàn)思路分析: 1.先保存占位文字顏色到系統(tǒng)類動(dòng)態(tài)添加的屬性. 2.取出動(dòng)態(tài)添加的placeholderColor給系統(tǒng)的占位文字Label設(shè)置字體顏色

  • 1.創(chuàng)建UITextField+Placeholder分類

  • 2.使用動(dòng)態(tài)添加placeholderColor屬性,用于存放占位文字的顏色.

    • 在UITextField+Placeholder.h中聲明@property UIColor *placeholderColor;,相當(dāng)于是聲明set,get方法.
    • 實(shí)現(xiàn)placeholderColor的set,get方法
      set方法中關(guān)聯(lián)動(dòng)態(tài)添加的屬性,使用objc_setAssociatedObject函數(shù)關(guān)聯(lián)動(dòng)態(tài)添加的屬性.
      使用KVC方式獲取文本框的占位文字的UILabel,并給占位文字的Label設(shè)置文本顏色.
      get方法中通過objc_getAssociatedObject函數(shù)獲取關(guān)聯(lián)的對(duì)象
  • 3.給系統(tǒng)的設(shè)置占位文字的setPlaceholder:方法添加功能.

    • 自定義實(shí)現(xiàn)wx_setPlaceholder:方法,該方法實(shí)現(xiàn)給系統(tǒng)的setPlaceholder:方法添加設(shè)置占位文本顏色的功能.
  • 4.交換系統(tǒng)方法: 在load類方法中實(shí)現(xiàn)自定義方法和系統(tǒng)方法交換.

    • 注意: 自定義的wx_setPlaceholder:方法系統(tǒng)的setPlaceholder:方法交換,注意別寫錯(cuò)要交換的系統(tǒng)方法的setPlaceholder:方法.

  • RunTime方式實(shí)現(xiàn)設(shè)置文本框占位文字顏色參考代碼
// ----------------------------------------------------------------------------
// TODO: TextField 方式三: 使用RunTime方式,通過分類設(shè)置文本框的占位文字顏色

// ----------------------------------------------------------------------------
// UITextField+PlaceholderColor.h文件
#import <UIKit/UIKit.h>

@interface UITextField (Placeholder)

/** 動(dòng)態(tài)添加placeholderColor屬性 */
@property UIColor *placeholderColor;

@end

// ----------------------------------------------------------------------------
// UITextField+PlaceholderColor.m文件
#import "UITextField+Placeholder.h"
#import <objc/message.h>

@implementation UITextField (PlaceholderColor)

#pragma =======================================================================
#pragma mark - RunTime實(shí)現(xiàn)交換方法

// ----------------------------------------------------------------------------
// 在load類方法中(類加載進(jìn)內(nèi)存的時(shí)候調(diào)用,只調(diào)用一次)
+ (void)load
{
    // 1.獲取要交互的方法 Method是C語言結(jié)構(gòu)體,不需要加*
    Method setPlaceholderMethod = class_getInstanceMethod(self, @selector(setPlaceholder:));
    Method wx_setPlaceholderMethod = class_getInstanceMethod(self, @selector(wx_setPlaceholder:));
    
    // 2.交換方法
    method_exchangeImplementations(setPlaceholderMethod, wx_setPlaceholderMethod);
}

// ----------------------------------------------------------------------------
// 給系統(tǒng)的方法添加設(shè)置占位文本顏色的功能
- (void)wx_setPlaceholder:(NSString *)placeholder
{
    // 1.調(diào)用交互方法,實(shí)際是調(diào)用setPlaceholderColor:方法
    [self wx_setPlaceholder:placeholder];
    
    // 2.設(shè)置保存的占位文字顏色
    self.placeholderColor = self.placeholderColor;
}

#pragma =======================================================================
#pragma mark - 使用RunTime實(shí)現(xiàn)關(guān)聯(lián)動(dòng)態(tài)添加的屬性placeholderColor
// ----------------------------------------------------------------------------
// 重寫set方法設(shè)置占位文本顏色
- (void)setPlaceholderColor:(UIColor *)placeholderColor
{
    // 1.關(guān)聯(lián)動(dòng)態(tài)placeholderColor添加的屬性,保存占位文字顏色到系統(tǒng)類動(dòng)態(tài)添加的placeholderColor屬性
    
    // object:保存到哪個(gè)對(duì)象中
    // key:屬性名
    // value:屬性值
    // policy:策略
    objc_setAssociatedObject(self, @"placeholderColor", placeholderColor, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
    
    // 2.使用KVC獲取占位文字的Label,并設(shè)置占位文字Label的字體顏色
    UILabel *placeholderLabel = [self valueForKeyPath:@"placeholderLabel"];
    placeholderLabel.textColor = placeholderColor;
}

// ----------------------------------------------------------------------------
// 重寫get方法獲取placeholderColor關(guān)聯(lián)的對(duì)象
- (UIColor *)placeholderColor
{
    return objc_getAssociatedObject(self, @"placeholderColor");
}
@end

2.我的界面搭建

  • 我的界面分析


    我的界面分析.png

只有storyboard才能設(shè)置靜態(tài)單元格(靜態(tài)cell),xib不能設(shè)置靜態(tài)單元格.


storyboard搭建我的界面(靜態(tài)cell)

  • 1.使用storyboard設(shè)置好靜態(tài)單元格

    • 需設(shè)置storyboard中控制器的管理類.
      設(shè)置storyboard中控制器的管理類.png
    • 刪除系統(tǒng)自動(dòng)生成的tableView數(shù)據(jù)源方法代碼.
  • 2.storyboard必須通過代碼加載

    • 方式一: 加載箭頭指向的控制器instantiateInitialViewController方法.
    // 在WXTabBarController.m中,添加子控制器的方法中
    // TODO: Storyboard加載控制器,storyboard必須手動(dòng)加載控制器
    UIStoryboard *storyboard = [UIStoryboard storyboardWithName:NSStringFromClass([WXMeViewController class]) bundle:nil];
    WXMeViewController *meVc = [storyboard instantiateInitialViewController];
    
    • 方式二: 加載指定標(biāo)識(shí)的控制器instantiateViewControllerWithIdentifier:方法.(在storyboard中必須設(shè)置StoryboardID)

我的界面底部板塊界面

  • UICollectionView的基本使用

    • 初始化時(shí)必須指定布局
      • 通過布局類設(shè)置cell的尺寸.
      • 使用布局設(shè)置最小行列間距,滾動(dòng)方法等.
    • 必須注冊(cè)cell
    • 必須自定義cell
  • tableView的注意點(diǎn)

    • 添加到tableView的footView的子控件不需要設(shè)置位置尺寸.

  • 1.設(shè)置底部tableFooterView為UICollectionView

// ----------------------------------------------------------------------------
// 常量和宏
static NSString * const ID = @"cell";
static NSInteger const colCount = 4;
static CGFloat const margin = 1;
#define cellWH ((screenW - margin * (colCount - 1)) / colCount)

// ----------------------------------------------------------------------------
// 設(shè)置底部tableFooterView
- (void)setupTableFooterView
{
    // ------------------------------------------------------------------------
    // 1.創(chuàng)建流水布局,設(shè)置cell的尺寸和行列最小間距
    UICollectionViewFlowLayout *flowLayout = [[UICollectionViewFlowLayout alloc] init];
    flowLayout.itemSize = CGSizeMake(cellWH, cellWH);
    flowLayout.minimumLineSpacing = margin;
    flowLayout.minimumInteritemSpacing = margin;
    
    // ------------------------------------------------------------------------
    // 2.創(chuàng)建collectionView,設(shè)置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.設(shè)置collectionView的數(shù)據(jù)源和代理
    collectionView.dataSource = self;
    collectionView.delegate = self;
    self.tableView.tableFooterView = collectionView;
    
    // ------------------------------------------------------------------------
    // 4.注冊(cè)cell
    [collectionView registerNib:[UINib nibWithNibName:NSStringFromClass([WXSquareCell class]) bundle:nil] forCellWithReuseIdentifier:ID];
}

  • 2.設(shè)置tableView的分組間距
    • 分組間距調(diào)整


      分組間距調(diào)整.png

  • 3.調(diào)整tableView分組間距

    • 最上面間距不屬于組頭部間距
    • 調(diào)整組尾部間距
    • 經(jīng)過分析,頂部的間距是第一個(gè)cell的y值為35,設(shè)置內(nèi)邊距左邊距為-25,這樣就能實(shí)現(xiàn)設(shè)置最頂部的間距為10;
    • 實(shí)現(xiàn)參考代碼
      // ----------------------------------------------------------------------------
      // 設(shè)置tableView的分組間距
      - (void)setSectionMargin
      {
          // 設(shè)置tableView的分組間距(調(diào)整分組的頭部尾部間距), 最頂部高度為35,通過設(shè)置內(nèi)邊距將最頂部間距設(shè)置為10
          self.tableView.sectionFooterHeight = 10;
          self.tableView.sectionHeaderHeight = 0;
          self.tableView.contentInset = UIEdgeInsetsMake(-25, 0, 0, 0);
      }
    

加載我板塊cell網(wǎng)絡(luò)數(shù)據(jù)

  • 1.使用AFN加載板塊cell網(wǎng)絡(luò)數(shù)據(jù)

    • 1.創(chuàng)建請(qǐng)求會(huì)話管理者
    • 2.拼接請(qǐng)求參數(shù)(必選參數(shù)一定要寫)
    • 3.發(fā)送請(qǐng)求

    • 請(qǐng)求板塊cell數(shù)據(jù)參考代碼
    // ----------------------------------------------------------------------------
    // 請(qǐng)求cell網(wǎng)絡(luò)數(shù)據(jù)
    - (void)loadData
    {
        // 1.創(chuàng)建請(qǐng)求會(huì)話管理者
        AFHTTPSessionManager *mgr = [AFHTTPSessionManager manager];
        
        // 2.拼接請(qǐng)求參數(shù)
        NSMutableDictionary *parameters = [NSMutableDictionary dictionary];
        parameters[@"a"] = @"square";
        parameters[@"c"] = @"topic";
        
        // 3.發(fā)送請(qǐng)求
        [mgr GET:baseUrl parameters:parameters progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
            
            // 3.1 字典數(shù)組轉(zhuǎn)模型數(shù)組
            self.squareList = [WXSquareItem mj_objectArrayWithKeyValuesArray:responseObject[@"square_list"]];
            
            // 3.2 處理請(qǐng)求的數(shù)據(jù)
            [self resolveData];
            
            // 3.3 刷新表格
            [self.collectionView reloadData];
            
            // 3.4 計(jì)算collectView的高度
            NSInteger count = self.squareList.count;
            // 3.4.1 計(jì)算行數(shù)
            NSInteger row = (count - 1) / colCount + 1;
            CGFloat collectionViewH = row * cellWH;
            self.collectionView.wx_height = collectionViewH;
            
            
            // TODO: 3.5 重新設(shè)置tableFooterView的顯示內(nèi)容,如果重新設(shè)置,會(huì)導(dǎo)致拖動(dòng)到最底部cell會(huì)自動(dòng)回彈
            self.tableView.tableFooterView = self.collectionView;
            
        } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
            NSLog(@"%@", error);
        }];
    }
  • 2.處理請(qǐng)求的數(shù)據(jù)

作用: 主要是用于補(bǔ)齊格子,不然未填充的格子會(huì)變成灰色的效果.

- 處理請(qǐng)求的數(shù)據(jù)實(shí)現(xiàn)代碼
  // ----------------------------------------------------------------------------
  // 處理請(qǐng)求的數(shù)據(jù)
  - (void)resolveData
  {
      // 如果數(shù)據(jù)不是4的倍數(shù),添加到4的倍數(shù).主要是用于補(bǔ)齊格子,不然未填充的格子會(huì)變成灰色的效果.
      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

    • 設(shè)置圖片和文字: 提供模型數(shù)據(jù),重寫set方法
      // ----------------------------------------------------------------------------
      // 重寫模型的set方法,設(shè)置圖片和文字
      - (void)setItem:(WXSquareItem *)item
      {
          _item = item;
          
          [self.iconImageView sd_setImageWithURL:[NSURL URLWithString:item.icon]];
          self.nameLabel.text = item.name;
      }
    
    • 實(shí)現(xiàn)點(diǎn)擊cell時(shí)閃爍效果
      // ----------------------------------------------------------------------------
      // WXSquareCell.m文件
      - (void)awakeFromNib {
          // 設(shè)置UICollectionViewCell選中時(shí)的背景色
          UIView *backView =  [[UIView alloc] init];
          backView.backgroundColor = WXColor(206, 206, 206);
          self.selectedBackgroundView = backView;
      }
      
      // ----------------------------------------------------------------------------
      // WXMeViewController.m文件
      - (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath
      {
          // 1.處理點(diǎn)擊閃爍
          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;
          });
          
          // 點(diǎn)擊跳轉(zhuǎn)網(wǎng)頁處理
      }
    

3.展示網(wǎng)頁的幾種實(shí)現(xiàn)方法

展示網(wǎng)頁: 1.WebView 2.openUrl
- WebView: 沒有自帶功能.好處: 就在當(dāng)前應(yīng)用下展示網(wǎng)頁.弊端: webView不能監(jiān)聽進(jìn)度條.
- safari: 自帶了很多功能,弊端: 必須要跳轉(zhuǎn)到其他應(yīng)用.


SFSafariViewController實(shí)現(xiàn)瀏覽展示網(wǎng)頁(iOS9之后才能使用)

  • SFSafariViewController實(shí)現(xiàn)展示網(wǎng)頁實(shí)現(xiàn)參考代碼
// 使用SFSafariViewController需導(dǎo)入SafariServices/SafariServices.h頭文件
#import <SafariServices/SafariServices.h>
// --------------------------------------------------------------------
// TODO: SFSafariViewController實(shí)現(xiàn)瀏覽展示網(wǎng)頁
// 3.1 創(chuàng)建Safari網(wǎng)頁控制器 iOS9才能用
SFSafariViewController *safariVc = [[SFSafariViewController alloc] initWithURL:[NSURL URLWithString:item.url]];
safariVc.delegate = self;

// 3.2 跳轉(zhuǎn)網(wǎng)頁控制器
[self presentViewController:safariVc animated:YES completion:nil];
safariVc.hidesBottomBarWhenPushed = YES;
[self.navigationController pushViewController:safariVc animated:YES];
  • SFSafariViewControllerDelegate代理方法
#pragma =======================================================================
#pragma mark - SFSafariViewControllerDelegat代理協(xié)議

// ----------------------------------------------------------------------------
// TODO: SFSafariViewController 監(jiān)聽Safari點(diǎn)擊完成按鈕
- (void)safariViewControllerDidFinish:(SFSafariViewController *)controller;

// ----------------------------------------------------------------------------
// TODO: SFSafariViewController 監(jiān)聽Safari初始化載入完成
- (void)safariViewController:(SFSafariViewController *)controller didCompleteInitialLoad:(BOOL)didLoadSuccessfully;

WKWebView實(shí)現(xiàn)展示網(wǎng)頁(iOS8之后才能使用)

  • WebKit框架的WKWebView展示網(wǎng)頁(iOS8之后才能使用)

    • 在工程文件中手動(dòng)導(dǎo)入WebKit框架
      • 使用WKWebView需先導(dǎo)入庫WebKit庫,否則會(huì)報(bào)錯(cuò)
        Undefined symbols for architecture x86_64:
        "OBJC_CLASS$_WKWebView", referenced from:
        工程文件中手動(dòng)導(dǎo)入WebKit框架 .png
    • KVO監(jiān)聽前進(jìn)后退刷新等屬性變化
    • KVO監(jiān)聽加載進(jìn)度.
    • KVO監(jiān)聽網(wǎng)頁標(biāo)題改變.
  • 自定義WKWebView

    • 1.使用xib布局網(wǎng)頁展示界面


      使用xib布局網(wǎng)頁展示界面.png
      • 在viewDidLayoutSubviews方法中重寫設(shè)置WKWebView的尺寸
        // ----------------------------------------------------------------------------
        // 控制器的view子控件布局完成調(diào)用
        - (void)viewDidLayoutSubviews
        {
            [super viewDidLayoutSubviews];
            
            // 1.設(shè)置wkWebView位置尺寸
            self.wkWebView.frame = self.htmlView.bounds;
        }
    
    • 2.提供一個(gè)url,讓外界傳遞要展示的url
    • 3.添加WXWebView到控制器的view,使用WKWebView的loadRequest:方法加載網(wǎng)頁
    // 通過傳遞的參數(shù)加載網(wǎng)頁
    NSURLRequest *request = [NSURLRequest requestWithURL:self.url];
    [wkWebView loadRequest:request];
    
    • 4.使用KVO添加監(jiān)聽后退,前進(jìn),進(jìn)度條,網(wǎng)頁標(biāo)題的改變
      #pragma =======================================================================
      #pragma mark - 監(jiān)聽后退,前進(jìn),進(jìn)度條,網(wǎng)頁標(biāo)題的監(jiān)聽
      
      // ----------------------------------------------------------------------------
      // 使用KVO添加監(jiān)聽
      - (void)setupAddObserver
      {
          // 1.添加后退,前進(jìn),進(jìn)度條,網(wǎng)頁標(biāo)題的監(jiān)聽
          [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];
      }
      
      // ----------------------------------------------------------------------------
      // 觀察的屬性有新值的時(shí)候就會(huì)調(diào)用
      - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context
      {
          // 1.更新后退,前進(jìn),進(jìn)度條,網(wǎng)頁標(biāo)題的監(jiān)聽
          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監(jiān)聽, 如果沒移除KVO監(jiān)聽,點(diǎn)擊返回會(huì)報(bào)錯(cuò)"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.點(diǎn)擊前進(jìn),后退,刷新按鈕執(zhí)行相應(yīng)操作
      • WKWebView的前進(jìn)goForward方法,后退goBack方法,刷新reload方法,
      #pragma =======================================================================
      #pragma mark - 監(jiān)聽后退,前進(jìn),刷新按鈕的點(diǎn)擊調(diào)用方法
      // ----------------------------------------------------------------------------
      // 后退按鈕點(diǎn)擊調(diào)用
      - (IBAction)back:(UIBarButtonItem *)sender {
          [self.wkWebView goBack];
      }
      
      // ----------------------------------------------------------------------------
      // 前進(jìn)按鈕點(diǎn)擊調(diào)用
      - (IBAction)forward:(UIBarButtonItem *)sender {
          [self.wkWebView goForward];
      }
      
      // ----------------------------------------------------------------------------
      // 刷新按鈕點(diǎn)擊調(diào)用
      - (IBAction)reload:(UIBarButtonItem *)sender {
          [self.wkWebView reload];
      }
    

4.設(shè)置界面


獲取SDWebImage緩存大小

  • SDWebImage獲取的圖片存放在Cache/default,獲取該目錄的緩存大小

    // 獲取SDWebImage緩存大小
    NSUInteger cacheSize = [[SDImageCache sharedImageCache] getSize];
    

封裝計(jì)算文件夾大小/移除文件夾所有文件業(yè)務(wù)類WXFileCacheManager

業(yè)務(wù)類: 常見業(yè)務(wù)類有網(wǎng)絡(luò)請(qǐng)求類,處理文件緩存類.
業(yè)務(wù)類命名: 類名可以以manager結(jié)尾.


獲取緩存大小原理(獲取文件夾下所有文件的大小)

  • 獲取文件夾的內(nèi)容屬于比較耗時(shí)的操作,最好放在異步子線程處理,避免導(dǎo)致UI操作卡頓.以下所有操作都放在異步子線程中執(zhí)行.

  • 封裝獲取文件夾大小的類方法

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

  • 2.判斷路徑參數(shù)是否存在并且是文件夾

    • 如果路徑不存在或不是文件夾, 拋出異常
  • 3.獲取文件夾下的所有文件子路徑

    • 調(diào)用NSFileManager 的對(duì)象方法subpathsAtPath:方法獲取文件夾下所有文件的子路徑
  • 4.遍歷文件夾下的所有文件,累計(jì)文件夾下的所有文件大小

    • 4.1 拼接全路徑
    • 4.2 過濾隱藏文件和文件夾: 判斷如果是隱藏文件帶有DS字符串,路徑不存在或不是文件夾路徑,則跳過
    • 4.3 獲取文件屬性,獲取文件大小
      *NSDictionary attr = [mgr attributesOfItemAtPath:fullPath error:nil];
      NSInteger fileSize = [attr[NSFileSize] integerValue];
    • 4.4 累計(jì)所有文件大小
  • 5.執(zhí)行計(jì)算完成后要處理的操作.執(zhí)行block.

因計(jì)算文件夾大小在異步子線程中執(zhí)行,為了獲得異步子線程計(jì)算文件夾大小的結(jié)果,可以讓封裝的方法傳入一個(gè)block參數(shù),讓子線程調(diào)用block方法,并將計(jì)算結(jié)果傳遞給外界.如果block內(nèi)部有刷新UI操作,必須在主線程調(diào)用block.
異步方法不需要設(shè)置返回值.

- 主線程回調(diào)執(zhí)行block參考代碼

```objectivec
dispatch_async(dispatch_get_main_queue(), ^{
    if (completeBlock) {
        completeBlock(totalSize);
    }
});
```

  • 獲取文件夾內(nèi)所有文件大小參考代碼
// ----------------------------------------------------------------------------
// TODO: 獲取文件夾大小
+ (void)getCacheSizeOfDirectoriesPath:(NSString *)directoriesPath completeBlock:(void(^)(NSInteger))completeBlock
{
    // ------------------------------------------------------------------------
    // 異步(子線程)計(jì)算文件大小,此操作比較耗時(shí),所以放在子線程計(jì)算
    dispatch_async(dispatch_get_global_queue(0, 0), ^{
        
        // 1.創(chuàng)建文件管理者
        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.遍歷文件夾下的所有文件,累計(jì)文件夾下的所有文件大小
        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 累計(jì)文件大小
            totalSize += fileSize;
            
        }
        
        // --------------------------------------------------------------------
        // 執(zhí)行主線程回調(diào),因?yàn)閎lock有刷新UI操作,所以必須在主線程執(zhí)行
        dispatch_async(dispatch_get_main_queue(), ^{
            if (completeBlock) {
                completeBlock(totalSize);
            }
        });
        
    });
}

移除文件夾下所有文件

  • 移除文件夾下所有文件的類方法
  • 移除文件夾的內(nèi)容屬于比較耗時(shí)的操作,最好放在異步子線程處理,避免導(dǎo)致UI操作卡頓.以下所有操作都放在異步子線程中執(zhí)行.
  • 1.使用[NSFileManager defaultManager];獲得文件管理者, NSFileManager是單例.
  • 2.判斷路徑參數(shù)是否存在并且是文件夾
    • 如果路徑不存在或不是文件夾, 拋出異常
  • 3.獲取文件夾下的所有文件子路徑
    • 調(diào)用NSFileManager 的對(duì)象方法subpathsAtPath:方法獲取文件夾下所有文件的子路徑
  • 4.遍歷文件夾下的所有文件,累計(jì)文件夾下的所有文件大小
    • 4.1 拼接全路徑
    • 4.2 移除文件
  • 5.執(zhí)行移除文件完成后要處理的操作.執(zhí)行block.

  • 移除文件夾下所有文件實(shí)現(xiàn)參考代碼
// ----------------------------------------------------------------------------
// TODO: 移除文件夾路徑下的所有文件
+ (void)removeDirectoriesPath:(NSString *)directoriesPath completeBlock:(void(^)())completeBlock
{
    // ------------------------------------------------------------------------
    // 異步(子線程)移除,此操作比較耗時(shí),所以放在子線程執(zhí)行
    dispatch_async(dispatch_get_global_queue(0, 0), ^{
        
        // 1.創(chuàng)建文件管理者
        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.執(zhí)行移除文件完成后要處理的操作.避免block里有執(zhí)行UI操作,最好在主線程下執(zhí)行
        dispatch_async(dispatch_get_main_queue(), ^{
            if (completeBlock) {
                completeBlock();
            }
        });
    });
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末臭杰,一起剝皮案震驚了整個(gè)濱河市搜囱,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌腋寨,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,042評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件沽讹,死亡現(xiàn)場(chǎng)離奇詭異兄墅,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)统刮,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,996評(píng)論 2 384
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來账千,“玉大人侥蒙,你說我怎么就攤上這事≡茸啵” “怎么了鞭衩?”我有些...
    開封第一講書人閱讀 156,674評(píng)論 0 345
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我醋旦,道長(zhǎng)恒水,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,340評(píng)論 1 283
  • 正文 為了忘掉前任饲齐,我火速辦了婚禮钉凌,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘捂人。我一直安慰自己御雕,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,404評(píng)論 5 384
  • 文/花漫 我一把揭開白布滥搭。 她就那樣靜靜地躺著酸纲,像睡著了一般。 火紅的嫁衣襯著肌膚如雪瑟匆。 梳的紋絲不亂的頭發(fā)上闽坡,一...
    開封第一講書人閱讀 49,749評(píng)論 1 289
  • 那天,我揣著相機(jī)與錄音愁溜,去河邊找鬼疾嗅。 笑死,一個(gè)胖子當(dāng)著我的面吹牛冕象,可吹牛的內(nèi)容都是我干的代承。 我是一名探鬼主播,決...
    沈念sama閱讀 38,902評(píng)論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼渐扮,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼论悴!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起墓律,我...
    開封第一講書人閱讀 37,662評(píng)論 0 266
  • 序言:老撾萬榮一對(duì)情侶失蹤膀估,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后耻讽,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體察纯,經(jīng)...
    沈念sama閱讀 44,110評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,451評(píng)論 2 325
  • 正文 我和宋清朗相戀三年齐饮,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片笤昨。...
    茶點(diǎn)故事閱讀 38,577評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡祖驱,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出瞒窒,到底是詐尸還是另有隱情捺僻,我是刑警寧澤,帶...
    沈念sama閱讀 34,258評(píng)論 4 328
  • 正文 年R本政府宣布,位于F島的核電站匕坯,受9級(jí)特大地震影響束昵,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜葛峻,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,848評(píng)論 3 312
  • 文/蒙蒙 一锹雏、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧术奖,春花似錦礁遵、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,726評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至唧龄,卻和暖如春兼砖,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背既棺。 一陣腳步聲響...
    開封第一講書人閱讀 31,952評(píng)論 1 264
  • 我被黑心中介騙來泰國打工讽挟, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人援制。 一個(gè)月前我還...
    沈念sama閱讀 46,271評(píng)論 2 360
  • 正文 我出身青樓戏挡,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國和親晨仑。 傳聞我的和親對(duì)象是個(gè)殘疾皇子褐墅,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,452評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn)洪己,斷路器妥凳,智...
    卡卡羅2017閱讀 134,628評(píng)論 18 139
  • 一 、使用git管理工程 1答捕、可以使用OSChina遠(yuǎn)程管理工程(免費(fèi)) 2逝钥、可以使用GitHub網(wǎng)站進(jìn)行遠(yuǎn)程管理...
    YuGHo閱讀 2,350評(píng)論 1 3
  • 發(fā)現(xiàn) 關(guān)注 消息 iOS 第三方庫、插件拱镐、知名博客總結(jié) 作者大灰狼的小綿羊哥哥關(guān)注 2017.06.26 09:4...
    肇東周閱讀 12,059評(píng)論 4 62
  • @(iOS 項(xiàng)目實(shí)戰(zhàn))[項(xiàng)目實(shí)戰(zhàn)] 作者: Liwx 郵箱: 1032282633@qq.com 目錄 05.項(xiàng)目...
    Liwx閱讀 893評(píng)論 0 2
  • 有人愿意為了愛飛蛾撲火艘款。我卻覺得這是自取滅亡
    veve柯殿閱讀 112評(píng)論 0 0