iOS常用

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小时搞定,结果做了两天,真是嚼一路辛苦,饮一路汗水!

上一篇下一篇

猜你喜欢

热点阅读