iOS中UITableviewCell上的音频播放笔记
2021-09-24 本文已影响0人
数字d
效果如图
1
需求:
1.每个头像下有一个播放按钮,点击播放,黑色的图标展示为动图效果(见第三行的效果)
2.正在播放的cell上的播放按钮再次点击会停止播放
3.有正在播放的cell,点击了其他cell上的按钮之后,停止正在播放的cell上的按钮,UI更新
4.避免cell复用导致的按钮播放图标展示错误
5.避免cell复用造成的动图和静态图的切换
6.播放远程的mp3音频卡顿问题
撸代码
tableview中的特殊处理
-(void)tableView:(UITableView *)tableView didEndDisplayingCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath {
YZPlayWithCell * cellGet = (YZPlayWithCell *)cell;
[cellGet setStopAnimation:NO];
}
-(void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath {
NSInteger row = [YZInstancePlayer sharedInstancePlayer].row;
YZPlayWithCell * cellGet = (YZPlayWithCell *)cell;
if (row == indexPath.row) {
[cellGet setStopAnimation:YES];
}else {
[cellGet setStopAnimation:NO];
}
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
YZPlayWithCell * cell = [YZPlayWithCell cellWithTableView:tableView];
cell.row = indexPath.row;
[cell setJokeDataStatus:YES];
return cell;
}
cell的实现,cell.h文件
@interface YZPlayWithCell : UITableViewCell
+ (instancetype)cellWithTableView:(UITableView *)tableView;
@property(nonatomic,assign)NSInteger row;
@property(nonatomic,assign)BOOL jokeDataStatus;
@property(nonatomic,assign)BOOL playStatus;
@property(nonatomic,assign)BOOL stopAnimation;
@end
cell.m文件
#import "YZPlayWithCell.h"
#import "YZLabelView.h"
@interface YZPlayWithCell()
@property(nonatomic,strong)UIView * rightZoneView;
@property(nonatomic,strong)UIImageView * avatarImageView;
@property(nonatomic,strong)UILabel * titleLab;
@property(nonatomic,strong)UIImageView * locationImageView;
@property(nonatomic,strong)UILabel * cityLab;
@property(nonatomic,strong)UIImageView * genderImageView;
@property(nonatomic,strong)YZLabelView * gradeLab;
@property(nonatomic,strong)YZLabelView * serverLab;
@property(nonatomic,strong)UILabel * detailLab;
@property(nonatomic,strong)UIView * liveBgView;
@property(nonatomic,strong)UIImageView * liveImageView;
@property(nonatomic,strong)YYAnimatedImageView * liveAnimationView;
@property(nonatomic,strong)UIView * voicePlayBgView;
@property(nonatomic,strong)UIButton * playBtn;
@property(nonatomic,strong)YYAnimatedImageView * playAnimationView;
@property(nonatomic,strong)UIImageView * playStaticView;
@property(nonatomic,strong)UILabel * playTimeLab;
@end
@implementation YZPlayWithCell
+ (instancetype)cellWithTableView:(UITableView *)tableView
{
static NSString *identifier = @"YZPlayWithCell";
// 1.缓存中取
YZPlayWithCell *cell = [tableView dequeueReusableCellWithIdentifier:identifier];
// 2.创建
if (cell == nil) {
cell = [[YZPlayWithCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:identifier];
}
cell.selectionStyle = UITableViewCellSelectionStyleNone;
cell.backgroundColor = UIColorHex(#EEEEEE);
return cell;
}
/**
* 构造方法(在初始化对象的时候会调用)
* 一般在这个方法中添加需要显示的子控件
*/
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self) {
[self.contentView addSubview:self.rightZoneView];
[self.contentView addSubview:self.avatarImageView];
[self.contentView addSubview:self.liveBgView];
self.liveBgView.hidden = YES;
[self.contentView addSubview:self.voicePlayBgView];
}
return self;
}
- (void)awakeFromNib {
[super awakeFromNib];
}
- (void)setSelected:(BOOL)selected animated:(BOOL)animated {
[super setSelected:selected animated:NO];
}
-(UIView *)rightZoneView {
if (_rightZoneView == nil) {
_rightZoneView = [[UIView alloc] initWithFrame:CGRectMake(70, 5, Screen_Width - 70 - 15, 90)];
_rightZoneView.backgroundColor = [UIColor whiteColor];
_rightZoneView.layer.cornerRadius = 8;
_rightZoneView.layer.masksToBounds = YES;
[_rightZoneView addSubview:self.cityLab];
[self.cityLab mas_makeConstraints:^(MASConstraintMaker *make) {
make.right.equalTo(_rightZoneView.mas_right).offset(-14);
make.top.equalTo(_rightZoneView.mas_top).offset(18);
make.width.equalTo(@30);
make.height.equalTo(@12);
}];
[_rightZoneView addSubview:self.locationImageView];
[self.locationImageView mas_makeConstraints:^(MASConstraintMaker *make) {
make.right.equalTo(self.cityLab.mas_left).offset(0);
make.centerY.equalTo(self.cityLab.mas_centerY);
make.width.equalTo(@6);
make.height.equalTo(@8);
}];
[_rightZoneView addSubview:self.titleLab];
[self.titleLab mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.equalTo(_rightZoneView.mas_left).offset(35);
make.bottom.equalTo(self.cityLab.mas_bottom);
make.height.equalTo(@15);
make.right.equalTo(self.locationImageView.mas_left).offset(-12);
}];
[_rightZoneView addSubview:self.genderImageView];
[self.genderImageView mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.equalTo(self.titleLab.mas_left);
make.top.equalTo(self.titleLab.mas_bottom).offset(7);
make.width.equalTo(@15);
make.height.equalTo(@15);
}];
[_rightZoneView addSubview:self.gradeLab];
[self.gradeLab mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.equalTo(self.genderImageView.mas_right).offset(4.5);
make.centerY.equalTo(self.genderImageView.mas_centerY);
make.width.equalTo(@50);
make.height.equalTo(@15);
}];
[_rightZoneView addSubview:self.serverLab];
[self.serverLab mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.equalTo(self.gradeLab.mas_right).offset(4);
make.height.equalTo(@15);
make.width.greaterThanOrEqualTo(@110);
make.centerY.equalTo(self.genderImageView.mas_centerY);
}];
[_rightZoneView addSubview:self.detailLab];
[self.detailLab mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.equalTo(self.genderImageView.mas_left);
make.top.equalTo(self.genderImageView.mas_bottom).offset(10);
make.height.equalTo(@12);
make.right.equalTo(_rightZoneView.mas_right).offset(-35);
}];
}
return _rightZoneView;
}
-(UILabel *)cityLab {
if (_cityLab == nil) {
_cityLab = [[UILabel alloc] init];
_cityLab.text = @"深圳";
_cityLab.textAlignment = NSTextAlignmentCenter;
_cityLab.font = [UIFont systemFontOfSize:10];
_cityLab.textColor = UIColorHex(#9595A6);
_cityLab.adjustsFontSizeToFitWidth = YES;
}
return _cityLab;
}
-(UIImageView *)locationImageView {
if (_locationImageView == nil) {
_locationImageView = [[UIImageView alloc] init];
_locationImageView.image = [UIImage imageNamed:@"yz_pw_icon_dingwei"];
}
return _locationImageView;
}
-(UILabel *)titleLab {
if (_titleLab == nil) {
_titleLab = [[UILabel alloc] init];
_titleLab.text = @"橘子汽水橘子汽水橘子汽水...";
_titleLab.textAlignment = NSTextAlignmentLeft;
_titleLab.font = [UIFont boldSystemFontOfSize:14];
_titleLab.textColor = UIColorHex(#303046);
}
return _titleLab;
}
-(UIImageView *)avatarImageView {
if (_avatarImageView == nil) {
_avatarImageView = [[UIImageView alloc] initWithFrame:CGRectMake(15, 10, 80, 80)];
[_avatarImageView sd_setImageWithURL:[NSURL URLWithString:@"https://thirdwx.qlogo.cn/mmopen/vi_32/DYAIOgq83epbyhsDOFZyT7j5wsbeygMM5t1fj53sYn1eFTibZMr3ek3PsVSKLKyLcAenbdDnuBC9HzXf8X5z2Sw/132"]];
_avatarImageView.layer.cornerRadius = 8;
_avatarImageView.layer.masksToBounds = YES;
}
return _avatarImageView;
}
-(UIImageView *)genderImageView {
if (_genderImageView == nil) {
_genderImageView = [[UIImageView alloc] init];
_genderImageView.image = [UIImage imageNamed:@"yz_pw_icon_Gender_woman"];
}
return _genderImageView;
}
-(YZLabelView *)gradeLab {
if (_gradeLab == nil) {
_gradeLab = [[YZLabelView alloc] initWithcolors:@[
(__bridge id)UIColorHex(#0E76F1).CGColor,
(__bridge id)UIColorHex(#3EB1FF).CGColor
]];
}
return _gradeLab;
}
- (YZLabelView *)serverLab {
if (_serverLab == nil) {
_serverLab = [[YZLabelView alloc] initWithcolors:@[
(__bridge id)UIColorHex(#E0AC3B).CGColor,
(__bridge id)UIColorHex(#E8C36A).CGColor
]];
}
return _serverLab;
}
-(UILabel *)detailLab {
if (_detailLab == nil) {
_detailLab = [[UILabel alloc] init];
_detailLab.text = @"娱乐游戏,用心体会娱乐游戏,用心体会娱乐游戏...";
_detailLab.textAlignment = NSTextAlignmentLeft;
_detailLab.font = [UIFont systemFontOfSize:10];
_detailLab.textColor = UIColorHex(#575779);
}
return _detailLab;
}
- (void)setJokeDataStatus:(BOOL)jokeDataStatus {
_jokeDataStatus = jokeDataStatus;
self.gradeLab.titleStr = @"王者荣耀";
self.serverLab.titleStr = @"服务40人 | 评分5.0";
self.liveBgView.hidden = !jokeDataStatus;
}
-(UIView *)liveBgView {
if (_liveBgView == nil) {
_liveBgView = [[UIView alloc] initWithFrame:CGRectMake(15, 25, 32, 13)];
// 半边圆角
UIBezierPath *maskPath = [UIBezierPath bezierPathWithRoundedRect:_liveBgView.bounds byRoundingCorners:UIRectCornerTopRight | UIRectCornerBottomRight cornerRadii:CGSizeMake(6.5,6.5)];
CAShapeLayer *maskLayer = [[CAShapeLayer alloc] init];
maskLayer.frame = _liveBgView.bounds;
maskLayer.path = maskPath.CGPath;
_liveBgView.layer.mask = maskLayer;
// 底色渐变
CAGradientLayer * layer = [[CAGradientLayer alloc] init];
layer.colors = @[
(__bridge id)UIColorHex(#0E76F1).CGColor,
(__bridge id)UIColorHex(#3EB1FF).CGColor,
];
layer.frame = CGRectMake(0, 0, 32, 13);
layer.startPoint = CGPointMake(0, 0);
layer.endPoint = CGPointMake(1, 0);
layer.locations = @[@(0.0),@(1.0f)];
[_liveBgView.layer addSublayer:layer];
[_liveBgView addSubview:self.liveImageView];
[_liveBgView addSubview:self.liveAnimationView];
}
return _liveBgView;
}
-(UIImageView *)liveImageView {
if (_liveImageView == nil) {
_liveImageView = [[UIImageView alloc] initWithFrame:CGRectMake(4, 2.5, 10, 8)];
_liveImageView.image = [UIImage imageNamed:@"yz_pw_icon_zhibo"];
}
return _liveImageView;
}
-(YYAnimatedImageView *)liveAnimationView {
if (_liveAnimationView == nil) {
NSString *filePath = [[NSBundle bundleWithPath:[[NSBundle mainBundle] bundlePath]] pathForResource:@"yz_white_play" ofType:@"gif"];
NSData *imageData = [NSData dataWithContentsOfFile:filePath];
YYImage * image = [[YYImage alloc] initWithData:imageData];
_liveAnimationView = [[YYAnimatedImageView alloc] initWithImage:image];
_liveAnimationView.frame = CGRectMake(17, 3, 10, 7);
[_liveAnimationView startAnimating];
}
return _liveAnimationView;
}
-(UIView *)voicePlayBgView {
if (_voicePlayBgView == nil) {
_voicePlayBgView = [[UIView alloc] initWithFrame:CGRectMake(20, 70, 51, 15)];
UIView * grayView = [[UIView alloc] initWithFrame:CGRectMake(8, 0, 43, 15)];
grayView.backgroundColor = UIColorHex(#E6F1FF);
UIBezierPath *maskPath = [UIBezierPath bezierPathWithRoundedRect:grayView.bounds byRoundingCorners:UIRectCornerBottomRight | UIRectCornerTopRight cornerRadii:CGSizeMake(7.5,7.5)];
CAShapeLayer *maskLayer = [[CAShapeLayer alloc] init];
maskLayer.frame = grayView.bounds;
maskLayer.path = maskPath.CGPath;
grayView.layer.mask = maskLayer;
[_voicePlayBgView addSubview:grayView];
[_voicePlayBgView addSubview:self.playBtn];
[_voicePlayBgView addSubview:self.playAnimationView];
[_voicePlayBgView addSubview:self.playTimeLab];
[_voicePlayBgView addSubview:self.playStaticView];
self.playStaticView.hidden = NO;
self.playAnimationView.hidden = YES;
}
return _voicePlayBgView;
}
-(UIButton *)playBtn {
if (_playBtn == nil) {
_playBtn = [UIButton buttonWithType:(UIButtonTypeCustom)];
_playBtn.frame = CGRectMake(0, 0, 15, 15);
[_playBtn setImage:[UIImage imageNamed:@"yz_pw_icon_player"] forState:(UIControlStateNormal)];
WS(weakSelf);
[[_playBtn rac_signalForControlEvents:(UIControlEventTouchUpInside)] subscribeNext:^(id x) {
[weakSelf setPlayStatus:!weakSelf.playStatus];
[weakSelf changeBtnAndAnimationStatus:weakSelf.playStatus];
}];
}
return _playBtn;
}
-(YYAnimatedImageView *)playAnimationView {
if (_playAnimationView == nil) {
NSString *filePath = [[NSBundle bundleWithPath:[[NSBundle mainBundle] bundlePath]] pathForResource:@"yz_black_play" ofType:@"gif"];
NSData *imageData = [NSData dataWithContentsOfFile:filePath];
YYImage * image = [[YYImage alloc] initWithData:imageData];
_playAnimationView = [[YYAnimatedImageView alloc] initWithImage:image];
_playAnimationView.frame = CGRectMake(19, 3, 14, 9);
}
return _playAnimationView;
}
-(UILabel *)playTimeLab {
if (_playTimeLab == nil) {
_playTimeLab = [[UILabel alloc] initWithFrame:CGRectMake(35, 2.5, 12, 10)];
_playTimeLab.text = @"6''";
_playTimeLab.textAlignment = NSTextAlignmentRight;
_playTimeLab.font = [UIFont boldSystemFontOfSize:9];
_playTimeLab.textColor = UIColorHex(#303046);
_playTimeLab.adjustsFontSizeToFitWidth = YES;
}
return _playTimeLab;
}
-(void)setPlayStatus:(BOOL)playStatus {
_playStatus = playStatus;
}
-(void)changeBtnAndAnimationStatus:(BOOL)status {
WS(weakSelf);
if (status) {
[_playBtn setImage:[UIImage imageNamed:@"yz_pw_icon_player_2"] forState:(UIControlStateNormal)];
self.playStaticView.hidden = YES;
self.playAnimationView.hidden = NO;
_playStatus = YES;
// [[YZInstancePlayer sharedInstancePlayer] playWithUrl:@"Faded - Alan Walker" localStatus:YES row:self.row stopBlock:^{
// [weakSelf stopAnimationAction];
// }];
NSString *urlStr = @"http://zhongyou-source.oss-cn-hangzhou.aliyuncs.com/file/2021/09/24/163247340633.mp3";
[[YZInstancePlayer sharedInstancePlayer] playWithUrl:urlStr localStatus:NO row:self.row stopBlock:^{
[weakSelf stopAnimationAction];
}];
}else {
[[YZInstancePlayer sharedInstancePlayer] playStop];
[weakSelf stopAnimationAction];
_playStatus = NO;
}
}
-(void)stopAnimationAction {
_playStatus = NO;
[_playBtn setImage:[UIImage imageNamed:@"yz_pw_icon_player"] forState:(UIControlStateNormal)];
self.playStaticView.hidden = NO;
self.playAnimationView.hidden = YES;
}
- (void)setStopAnimation:(BOOL)stopAnimation {
_stopAnimation = stopAnimation;
if (stopAnimation && self.playStatus) {
self.playAnimationView.hidden = NO;
self.playStaticView.hidden = YES;
[_playBtn setImage:[UIImage imageNamed:@"yz_pw_icon_player_2"] forState:(UIControlStateNormal)];
}else {
self.playAnimationView.hidden = YES;
self.playStaticView.hidden = NO;
[_playBtn setImage:[UIImage imageNamed:@"yz_pw_icon_player"] forState:(UIControlStateNormal)];
}
}
-(UIImageView *)playStaticView {
if (_playStaticView == nil) {
_playStaticView = [[UIImageView alloc] initWithFrame:CGRectMake(19, 3, 14, 9)];
_playStaticView.image = [UIImage imageNamed:@"yz_pw_icon_Playbar"];
}
return _playStaticView;
}
@end
播放器的单例实现
播放器的.h文件
#import <Foundation/Foundation.h>
#import <AVFoundation/AVFoundation.h>
NS_ASSUME_NONNULL_BEGIN
@interface YZInstancePlayer : NSObject
@property(nonatomic,assign)NSInteger row;
+ (instancetype)sharedInstancePlayer;
-(void)playWithUrl:(NSString *)url localStatus:(BOOL)status row:(NSInteger)row stopBlock:(YZNullBasicBlock)stopBlock;
-(void)playStop;
@end
NS_ASSUME_NONNULL_END
播放器的.m文件
#import "YZInstancePlayer.h"
#import "DownLoadRequest.h"
static YZInstancePlayer *instance = nil;
@interface YZInstancePlayer()<AVAudioPlayerDelegate>
@property(nonatomic,strong)AVAudioPlayer * yzPlayer;
@property(nonatomic,copy)YZNullBasicBlock stopBlock;
@property(nonatomic,strong)DownLoadRequest * down;
@end
@implementation YZInstancePlayer
+ (instancetype)sharedInstancePlayer {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
instance = [[YZInstancePlayer alloc] init];
});
return instance;
}
-(id)init
{
self = [super init];
if (self) {
}
return self;
}
-(void)playWithUrl:(NSString *)url localStatus:(BOOL)status row:(NSInteger)row stopBlock:(YZNullBasicBlock)stopBlock {
[self playStop];
_stopBlock = stopBlock;
_row = row;
if (status) {
self.yzPlayer= [[AVAudioPlayer alloc] initWithContentsOfURL:[[NSBundle mainBundle] URLForResource:url withExtension:@"mp3"] error:nil];
[self.yzPlayer prepareToPlay];
self.yzPlayer.delegate = self;
[self.yzPlayer play];
}else {
// dispatch_queue_t serialQueue = dispatch_queue_create("yz.serial.Queue", DISPATCH_QUEUE_SERIAL);
// dispatch_async(serialQueue, ^{
// NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:@"http://zhongyou-source.oss-cn-hangzhou.aliyuncs.com/file/2021/09/24/163247340633.mp3"]];
// self.yzPlayer = [[AVAudioPlayer alloc] initWithData:data error:nil];
// [self.yzPlayer prepareToPlay];
// self.yzPlayer.delegate = self;
// [self.yzPlayer play];
// });
[self downWithUrl:url];
//播放本地音乐
}
}
-(void)playStop {
if (self.yzPlayer && self.yzPlayer.isPlaying) {
[self.yzPlayer stop];
_stopBlock();
}
}
- (void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:(BOOL)flag {
NSLog(@"%d %d",player.isPlaying, flag);
if (flag) {
_stopBlock();
}
}
-(void)downWithUrl:(NSString *)urlStr {
NSFileManager *fileManager = [NSFileManager defaultManager];
if ([fileManager fileExistsAtPath:ZFileDownloadPath]) {
[fileManager removeItemAtPath:ZFileDownloadPath error:nil];
}
self.down = nil;
WS(weakSelf);
self.down = [[DownLoadRequest alloc]initWithURL:urlStr Path:ZFileDownloadPath];
[self.down BegindownProgress:^(long long totalReceivedContentLength, long long totalContentLength) {} Succeed:^(NSString *URL, NSString *path) {
NSLog(@"%@",path);
AVAudioSession *audioSession = [AVAudioSession sharedInstance];
[audioSession setCategory:AVAudioSessionCategoryPlayback error:nil];
[audioSession setActive:YES error:nil];
NSURL *url = [NSURL fileURLWithPath:path];
weakSelf.yzPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:url error:nil];
[weakSelf.yzPlayer prepareToPlay];
weakSelf.yzPlayer.delegate = weakSelf;
[weakSelf.yzPlayer play];
} Failure:^{
}];
}
@end
downLoadurl方法可替换成
-(void)playRemoteUrl:(NSString *)url {
dispatch_queue_t serialQueue = dispatch_queue_create("yz.serial.Queue", DISPATCH_QUEUE_SERIAL);
dispatch_async(serialQueue, ^{
NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:url]];
self.yzPlayer = [[AVAudioPlayer alloc] initWithData:data error:nil];
[self.yzPlayer prepareToPlay];
self.yzPlayer.delegate = self;
[self.yzPlayer play];
});
}
这里调试时候卡死是必现的,所以添加了
远程mp3文件的下载类实现,failblock待实现,暂时忽略,未来补充
#import <Foundation/Foundation.h>
#define ZFileDownloadPath [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject] stringByAppendingPathComponent:@"MyDownloadFile.mp3"]
@interface DownLoadRequest : NSObject
/**
* URL 下载链接
* Path 下载存放路径,如果程序退出,下次传入的路径和上一次一样,可以继续断点下载
*/
- (instancetype)initWithURL:(NSString *)URL Path:(NSString *)path;
/**
* 下载回调
*/
-(void)BegindownProgress:(void (^)(long long totalReceivedContentLength, long long totalContentLength))progress Succeed:(void(^)(NSString * URL, NSString * path))succeed Failure:(void(^)())failure;
/**
* 取消下载
*/
-(void)cancelLoad;
/**
* 开始下载
*/
-(void)startLoad;
//-(void)deleteAllFile;
@end
下载类的.m文件实现
#import "DownLoadRequest.h"
typedef void (^ProgressBlock)();
typedef void (^SucceedBlock)();
//typedef void (^FailureBlock)();
@interface DownLoadRequest()
/**
* 请求
*/
@property (strong , nonatomic) NSURLConnection * Connection;
/**
* 用来写数据的文件句柄对象
*/
@property (nonatomic, strong) NSFileHandle * writeHandle;
/**
* 下载链接
*/
@property (nonatomic, copy) NSString * URL;
/**
* 存放路径
*/
@property (nonatomic, copy) NSString * path;
/**
* 进度回调
*/
@property(nonatomic, copy) ProgressBlock progressBlock;
/**
* 下载成功回调
*/
@property (nonatomic, copy) SucceedBlock succeedBlock;
/**
* 下载失败回调
*/
@property (nonatomic, copy) FailureBlock failureBlock;
/**
* 总的长度
*/
@property (nonatomic, assign) NSInteger totalexpectedContentLength;
/**
* 当前已经写入的长度
*/
@property (nonatomic, assign) NSInteger totalReceivedContentLength;
@end
@implementation DownLoadRequest
- (instancetype)initWithURL:(NSString *)URL Path:(NSString *)path
{
self = [super init];
if (self) {
_path = path;
_URL = URL;
}
return self;
}
/**
* 开始下载
*/
-(void)BegindownProgress:(void (^)(long long totalReceivedContentLength, long long totalContentLength))progress Succeed:(void(^)(NSString * URL, NSString * path))succeed Failure:(void(^)())failure
{
__weak __typeof (self)weakself = self;
[self setProgressBlockWithProgress:progress];
self.succeedBlock=^()
{
succeed(weakself.URL, weakself.path);
};
// self.failureBlock = ^{
// failure();
// };
[self startLoad];
}
//进度条回调
-(void)setProgressBlockWithProgress:(void (^)(long long totalReceivedContentLength, long long totalContentLength))progress
{
__weak __typeof (self)weakself = self;
self.progressBlock = ^{
if (progress != nil)
{
dispatch_async(dispatch_get_main_queue(), ^{
progress(weakself.totalReceivedContentLength, weakself.totalexpectedContentLength);
});
}
};
}
/**
* 建立音频下载请求
*/
-(void)HTTPDownLoadReaquest
{
NSURL *url=[NSURL URLWithString:self.URL];
//创建一个请求
NSURLRequest *request = [NSURLRequest requestWithURL:url];
self.Connection = [[NSURLConnection alloc] initWithRequest:request delegate:self startImmediately:NO];
}
/**
* 断点请求
*/
-(void)HTTPDownLoadPoint
{
NSURL *url=[NSURL URLWithString:_URL];
//创建一个请求
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
NSString *range = [NSString stringWithFormat:@"bytes=%llu-",[self fileSizeForPath:_path]];
[request setValue:range forHTTPHeaderField:@"Range"];
//使用代理发送异步请求
self.Connection = [NSURLConnection connectionWithRequest:request delegate:self];
}
/**
* 获取文件路径
*/
- (long long)fileSizeForPath:(NSString *)path
{
long long fileSize = 0;
NSFileManager *fileManager = [NSFileManager new];
if ([fileManager fileExistsAtPath:path])
{
NSError *error = nil;
NSDictionary *fileDict = [fileManager attributesOfItemAtPath:path error:&error];
if (!error && fileDict)
{
fileSize = [fileDict fileSize];
}
}
return fileSize;
}
//- (void)deleteAllFile
//{
// NSFileManager *fileManager = [NSFileManager defaultManager];
// if ([fileManager fileExistsAtPath:_path]) {
//
// // 删除沙盒中所有资源
// [fileManager removeItemAtPath:_path error:nil];
// }
//}
/**
* 取消下载
*/
-(void)cancelLoad
{
[self.Connection cancel];
}
/**
* 开始下载
*/
-(void)startLoad
{
[self.Connection cancel];
if ([self fileSizeForPath:_path] > 0)
{
[self HTTPDownLoadPoint];
}
else
{
[self HTTPDownLoadReaquest];
}
[self.Connection start];
}
/*
*当接收到服务器的响应(连通了服务器)时会调用
*/
-(void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
self.totalexpectedContentLength = 0;
self.totalReceivedContentLength = 0;
if ([self fileSizeForPath:_path] == 0)
{
// 创建一个用来写数据的文件句柄对象
NSFileManager* mgr = [NSFileManager defaultManager];
[mgr createFileAtPath:_path contents:nil attributes:nil];
}
self.totalReceivedContentLength = [self fileSizeForPath:_path];
self.totalexpectedContentLength = response.expectedContentLength + [self fileSizeForPath:_path];
self.writeHandle = [NSFileHandle fileHandleForWritingAtPath:_path];
}
/*
*当接收到服务器的数据时会调用(可能会被调用多次,每次只传递部分数据)
*/
-(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
// 移动到文件的最后面
[self.writeHandle seekToEndOfFile];
// 将数据写入沙盒
[self.writeHandle writeData:data];
self.totalReceivedContentLength += data.length;
self.progressBlock();
}
/*
*当服务器的数据加载完毕时就会调用
*/
-(void)connectionDidFinishLoading:(NSURLConnection *)connection
{
[self.writeHandle closeFile];
self.writeHandle = nil;
self.succeedBlock();
}
/*
*请求错误(失败)的时候调用(请求超时\断网\没有网\,一般指客户端错误)
*/
-(void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
// self.failureBlock();
}
@end
小小的一个cell本来以为2小时搞定,结果做了两天,真是嚼一路辛苦,饮一路汗水!