美文网首页iOS常用
iOS中UITableviewCell上的音频播放笔记

iOS中UITableviewCell上的音频播放笔记

作者: 数字d | 来源:发表于2021-09-24 18:27 被阅读0次

    效果如图


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

    相关文章

      网友评论

        本文标题:iOS中UITableviewCell上的音频播放笔记

        本文链接:https://www.haomeiwen.com/subject/rwizgltx.html