歡迎訪問我的博客muhlenXi,該文章出自我的博客。
版權(quán)聲明:本文為muhlenXi原創(chuàng)文章,轉(zhuǎn)載請(qǐng)注明出處,未經(jīng)允許不得轉(zhuǎn)載.
導(dǎo)語(yǔ):
也許你也注意到了,現(xiàn)在很多App在啟動(dòng)頁(yè)加載完畢后,還會(huì)出現(xiàn)一個(gè)n秒的廣告頁(yè)面,頁(yè)面中有一個(gè)倒計(jì)時(shí)的按鈕,我們可以通過點(diǎn)擊跳過那個(gè)按鈕來(lái)跳過,我們點(diǎn)擊廣告的時(shí)候,會(huì)進(jìn)入廣告的詳情頁(yè)面。如果我們不做任何操作的話,當(dāng)?shù)褂?jì)時(shí)為0秒是會(huì)自動(dòng)進(jìn)入主頁(yè)面。
接下來(lái)我們就研究研究這個(gè)是如何實(shí)現(xiàn)的。
解決方案
我們仔細(xì)想想:不妨也有兩種思路來(lái)解決。
1、一種是App初次運(yùn)行時(shí),將廣告頁(yè)面的圖片URL和要點(diǎn)擊廣告要跳轉(zhuǎn)的URL數(shù)據(jù)通過服務(wù)器下載下來(lái),然后再異步下載圖片數(shù)據(jù),最后將圖片的數(shù)據(jù)和跳轉(zhuǎn)URL保存到本地沙盒中。第二次運(yùn)行App的時(shí)候會(huì)顯示廣告界面,這時(shí)候再通過服務(wù)器更新本地沙盒中的數(shù)據(jù)。第一次由于本地沙盒中沒有數(shù)據(jù)則不會(huì)顯示。目前大部分App采用此方式
-
2、第二種是每次啟動(dòng)時(shí)就通過服務(wù)器異步下載圖片數(shù)據(jù)和跳轉(zhuǎn)URL,然后將其顯示出來(lái)。這樣做的優(yōu)點(diǎn)時(shí),可以實(shí)時(shí)更新廣告頁(yè)面數(shù)據(jù)。缺點(diǎn)是當(dāng)網(wǎng)絡(luò)出現(xiàn)阻塞時(shí)或無(wú)網(wǎng)絡(luò)時(shí),會(huì)出現(xiàn)一個(gè)空白的廣告界面。
針對(duì)該缺點(diǎn),有一個(gè)解決思路,就是當(dāng)網(wǎng)絡(luò)不好時(shí),用一個(gè)固定的圖片和跳轉(zhuǎn)URL來(lái)替換或者只用一個(gè)固定的圖片來(lái)替換,點(diǎn)擊廣告則不跳轉(zhuǎn)。但是當(dāng)跳轉(zhuǎn)URL失效時(shí),需要通過迭代版本,重新上架來(lái)更新,周期比較長(zhǎng)。
第一種方案。
XYJAdvertisementView的實(shí)現(xiàn)
在Xcode中通過File -> New ->File... 新建一個(gè)繼承與UIVIew的XYJLaunchAdvertisingView;
編寫程序的核心在于要有一個(gè)完整的思路!其次為了高效率的編程,我們需要學(xué)會(huì)一些偷懶的方法,比如宏定義的使用、類型常量的使用、變量的高效命名...
【1】在XYJAdvertisementView.h文件中,我們需要幾個(gè)宏定義和類型常量。代碼如下:
#define kScreenWidth [UIScreen mainScreen].bounds.size.width
#define kScreenHeight [UIScreen mainScreen].bounds.size.height
#define kScreenBounds [UIScreen mainScreen].bounds
static NSString * const adImageName = @"adImageName";
static NSString * const adDownloadUrl = @"adDownloadUrl";
static NSInteger const adTime = 3;
static NSString * const pushToADNotiName = @"pushToADNotiName";
static NSString * const pushToADUrl = @"pushToADUrl";
我們還需聲明一個(gè)圖片路徑和一個(gè)顯示廣告的show方法。
@property (nonatomic,copy) NSString * filePath; //!< ?圖片路徑 用于屬性傳值
- (void) showAD; //顯示廣告頁(yè)面方法
【2】在XYJAdvertisementView.m文件中,在匿名類中聲明我們需要的控件。
聲明如下:
@property (nonatomic,strong) UIImageView * adImageView;
@property (nonatomic,strong) UIButton * countBtn; //倒計(jì)時(shí)
@property (nonatomic,strong) NSTimer * countTimer;
@property (nonatomic,assign) NSInteger count; //記錄當(dāng)前的秒數(shù)
接下來(lái)我們依次實(shí)現(xiàn)相應(yīng)的方法,我們要記住高內(nèi)聚低耦合的原則
通過重寫initWithFrame方法來(lái)搭建我們的UI界面
- (instancetype)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
//其他控件的初始化寫在這里
//1.廣告圖片
_adImageView = [[UIImageView alloc] initWithFrame:frame];
_adImageView.userInteractionEnabled = YES;
_adImageView.backgroundColor = [UIColor yellowColor];
_adImageView.contentMode = UIViewContentModeScaleAspectFill;
_adImageView.clipsToBounds = YES;
UITapGestureRecognizer * tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapGesHandle:)];
[_adImageView addGestureRecognizer:tap];
//2.跳過按鈕
CGFloat btnW = 60.0f;
CGFloat btnH = 30.0f;
_countBtn = [[UIButton alloc] initWithFrame:CGRectMake(kScreenWidth-btnW-24, btnH, btnW, btnH)];
[_countBtn addTarget:self action:@selector(dismissAD) forControlEvents:UIControlEventTouchUpInside];
_countBtn.titleLabel.font = [UIFont systemFontOfSize:15];
[_countBtn setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
[_countBtn setTitle:[NSString stringWithFormat:@"跳過%ld",adTime] forState:UIControlStateNormal];
_countBtn.backgroundColor = [UIColor colorWithRed:38/255.0 green:38/255.0 blue:38/255.0 alpha:0.6];
_countBtn.layer.cornerRadius = 4;
[self addSubview:_adImageView];
[self addSubview:_countBtn];
}
return self;
}
-
通過
懶加載的方式實(shí)現(xiàn)我們的定時(shí)器countTimer*所謂的懶加載也就是延時(shí)加載,即當(dāng)對(duì)象需要用到的時(shí)候再去加載,簡(jiǎn)單理解就是,重寫對(duì)象的get方法。當(dāng)我們重寫get方法時(shí),一定要注意,先要判斷當(dāng)前對(duì)象是否為空,為空的話再去實(shí)例化對(duì)象。
懶加載的優(yōu)點(diǎn)如下:
1、對(duì)象的實(shí)例化在get方法中實(shí)現(xiàn),可以降低耦合度。
2、不需要在viewDidLoad中再實(shí)例化對(duì)象,可以簡(jiǎn)化代碼,同時(shí)增強(qiáng)代碼的可讀性。
3、有效減少內(nèi)存的占用率。
代碼如下:
- (NSTimer *)countTimer
{
if (_countTimer == nil) {
_countTimer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(countDownEventHandle) userInfo:nil repeats:YES];
}
return _countTimer;
}
實(shí)現(xiàn)我們的事件響應(yīng)方法
//廣告界面點(diǎn)擊
- (void) tapGesHandle:(UITapGestureRecognizer *) tap
{
[self dismissAD];
[[NSNotificationCenter defaultCenter] postNotificationName:pushToADNotiName object:nil userInfo:nil];
}
//定時(shí)器響應(yīng)
- (void) countDownEventHandle
{
_count--;
[_countBtn setTitle:[NSString stringWithFormat:@"跳過%ld",_count] forState:UIControlStateNormal];
if (_count == 0) {
[self dismissAD];
}
}
//跳過按鈕觸發(fā)
- (void) dismissAD
{
[self.countTimer invalidate];
self.countTimer = nil;
[UIView animateWithDuration:0.3 animations:^{
self.alpha = 0;
} completion:^(BOOL finished) {
[self removeFromSuperview];
}];
}
實(shí)現(xiàn)我們前面聲明的Show方法
//啟動(dòng)定時(shí)器
- (void) startTimer
{
_count = adTime;
[[NSRunLoop mainRunLoop] addTimer:self.countTimer forMode:NSRunLoopCommonModes];
}
//顯示廣告頁(yè)面
- (void)showAD
{
[self startTimer];
UIWindow * window = [UIApplication sharedApplication].keyWindow;
[window addSubview:self];
}
//圖片賦值
- (void)setFilePath:(NSString *)filePath
{
_filePath = filePath;
_adImageView.image = [UIImage imageWithContentsOfFile:filePath];
}
到這里,我們的View就定制完成,我們還需要一個(gè)數(shù)據(jù)管理類來(lái)管理沙盒中的廣告數(shù)據(jù)!
數(shù)據(jù)管理類XYJADDataManager的實(shí)現(xiàn)
通過File -> New ->File... 新建一個(gè)繼承與NSObject的XYJADDataManager;
【1】在XYJADDataManager.h文件中,聲明一個(gè)添加廣告的方法聲明。代碼如下:
導(dǎo)入頭文件:
#import "XYJAdvertisementView.h"
方法聲明:
+ (void) addXYJAdvertisementView;
【2】在XYJADDataManager.m文件中,實(shí)現(xiàn)相應(yīng)的方法。代碼如下:
在實(shí)現(xiàn)show方法之前,我們要先實(shí)現(xiàn)一些幫助方法
通過圖片的名字獲取該圖片在沙盒中的絕對(duì)路徑
+ (NSString *)getFilePathWithImageName:(NSString *)imageName
{
if (imageName) {
NSArray * paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
//圖片默認(rèn)存儲(chǔ)在Cache目錄下
return [paths[0] stringByAppendingPathComponent:imageName];
}
return nil;
}
判斷該路徑下是否存在文件
+ (BOOL)isFileExistWithFilePath:(NSString *) filePath
{
NSFileManager * fileManager = [NSFileManager defaultManager];
BOOL isDirectory = NO;
return [fileManager fileExistsAtPath:filePath isDirectory:&isDirectory];
}
刪除舊的圖片
+ (void) deleteOldImage
{
NSString * imageName = [[NSUserDefaults standardUserDefaults] objectForKey:adImageName];
if (imageName) {
NSString * filePath = [self getFilePathWithImageName:imageName];
NSFileManager * fileManager = [NSFileManager defaultManager];
if ([self isFileExistWithFilePath:filePath]) {
[fileManager removeItemAtPath:filePath error:nil];
}
}
}
向服務(wù)器請(qǐng)求廣告數(shù)據(jù)
該方法中要根據(jù)實(shí)際項(xiàng)目需求做相應(yīng)調(diào)整
+ (void) UpdateAdvertisementDataFromServer
{
//TODO 在這里請(qǐng)求廣告的數(shù)據(jù),包含圖片的圖片路徑和點(diǎn)擊圖片要跳轉(zhuǎn)的URL
//我們這里假設(shè)從服務(wù)器中獲得的 圖片的下載URl和跳轉(zhuǎn)URl如下所示
NSString * imageurl = @"http://pic.paopaoche.net/up/2012-2/20122220201612322865.png";
NSString * pushtoURl = @"http://www.itdecent.cn";
//獲取圖片名
NSString * imageName = [[imageurl componentsSeparatedByString:@"/"] lastObject];
//將圖片名與沙盒中的數(shù)據(jù)比較
NSString * oldImageName =[[NSUserDefaults standardUserDefaults] objectForKey:adImageName];
if ((oldImageName == nil) || (![oldImageName isEqualToString:imageName]) ) {
//異步下載廣告數(shù)據(jù)
[self downloadADImageWithUrl:imageurl iamgeName:imageName];
//保存跳轉(zhuǎn)路徑到沙盒中
[[NSUserDefaults standardUserDefaults] setObject:pushtoURl forKey:pushToADUrl];
[[NSUserDefaults standardUserDefaults] synchronize];
}
}
異步下載圖片數(shù)據(jù)
+ (void) downloadADImageWithUrl:imageUrl iamgeName:(NSString *) imageName
{
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
//TODO 異步操作
//1、下載數(shù)據(jù)
NSData * data = [NSData dataWithContentsOfURL:[NSURL URLWithString:imageUrl]];
UIImage * image = [UIImage imageWithData:data];
//2、獲取保存文件的路徑
NSString * filePath = [self getFilePathWithImageName:imageName];
//3、寫入文件到沙盒中
BOOL ret = [UIImagePNGRepresentation(image) writeToFile:filePath atomically:YES];
if (ret) {
NSLog(@"廣告圖片保存成功");
[self deleteOldImage];
//保存?圖片名和下載路徑
[[NSUserDefaults standardUserDefaults] setObject:imageName forKey:adImageName];
[[NSUserDefaults standardUserDefaults] setObject:imageUrl forKey:adDownloadUrl];
[[NSUserDefaults standardUserDefaults] synchronize];
} else {
NSLog(@"廣告圖片保存失敗");
}
});
}
實(shí)現(xiàn)addXYJAdvertisementView方法
+ (void) addXYJAdvertisementView;
{
//1.判斷沙盒中是否存在廣告的圖片名字和圖片數(shù)據(jù),如果有則顯示
NSString * imageName = [[NSUserDefaults standardUserDefaults] objectForKey:adImageName];
if (imageName != nil)
{
NSString * filePath = [self getFilePathWithImageName:imageName];
BOOL isExist = [self isFileExistWithFilePath:filePath];
//本地存在圖片
if (isExist) {
NSLog(@"本地存在圖片");
XYJAdvertisementView * adView = [[XYJAdvertisementView alloc] initWithFrame:kScreenBounds];
adView.filePath = filePath;
[adView showAD];
}
}
//更新本地廣告數(shù)據(jù)
[self UpdateAdvertisementDataFromServer];
}
最后一步,在AppDelegate文件中添加廣告
- 1、在
AppDelegate.h文件中導(dǎo)入XYJADDataManager.h文件 。 - 2、在
didFinishLaunchingWithOptions方法中加入如下代碼即可。
//添加啟動(dòng)廣告
[XYJADDataManager addXYJAdvertisementView];
- 3、如果你需要獲取廣告點(diǎn)擊事件,則需要進(jìn)行如下操作。
在主界面ViewController的viewDidLoad方法中添加:
//添加廣告點(diǎn)擊的監(jiān)聽
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(pushToADVC) name:pushToADNotiName object:nil];
同時(shí)實(shí)現(xiàn)事件響應(yīng)方法:
- (void) pushToADVC
{
//TODO 在這里處理廣告事件響應(yīng)
NSLog(@"廣告點(diǎn)擊了");
XYJADWebViewController * webVC = [[XYJADWebViewController alloc] init];
webVC.url = [[NSUserDefaults standardUserDefaults] objectForKey:pushToADUrl];
[self.navigationController pushViewController:webVC animated:YES];
}
編譯運(yùn)行后,會(huì)發(fā)現(xiàn)跟我們前面的效果展示是一樣的。
目前暫無(wú)實(shí)現(xiàn)第二種方案
感謝閱讀,有什么建議可以給我留言