@(iOS 項(xiàng)目實(shí)戰(zhàn))[項(xiàng)目實(shí)戰(zhàn)]
- 作者: Liwx
- 郵箱: 1032282633@qq.com
目錄
- 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屬性名
- 使用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ì)象
- 在UITextField+Placeholder.h中聲明
-
3.
給系統(tǒng)的設(shè)置占位文字的setPlaceholder:方法添加功能
.- 自定義實(shí)現(xiàn)
wx_setPlaceholder:方法,該方法實(shí)現(xiàn)給系統(tǒng)的setPlaceholder:方法添加設(shè)置占位文本顏色的功能
.
- 自定義實(shí)現(xiàn)
-
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.我的界面搭建
-
我的界面分析
只有
storyboard才能設(shè)置靜態(tài)單元格
(靜態(tài)cell),xib不能設(shè)置靜態(tài)單元格
.
storyboard搭建我的界面(靜態(tài)cell)
-
1.使用storyboard設(shè)置好靜態(tài)單元格
- 需設(shè)置
storyboard中控制器的管理類
.
-
刪除系統(tǒng)自動(dòng)生成的tableView數(shù)據(jù)源方法代碼
.
- 需設(shè)置
-
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
- 初始化時(shí)必須指定
-
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)整
-
-
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.(適配不同屏幕)布局視圖
- 設(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:
- 使用WKWebView需先導(dǎo)入庫WebKit庫,否則會(huì)報(bào)錯(cuò)
- KVO監(jiān)聽前進(jìn)后退刷新等屬性變化
- KVO監(jiān)聽加載進(jìn)度.
- KVO監(jiān)聽網(wǎng)頁標(biāo)題改變.
- 在工程文件中手動(dòng)
-
自定義WKWebView
-
1.使用xib布局網(wǎng)頁展示界面
- 在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方法
,
- WKWebView的
#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();
}
});
});
}