当前位置: 首页 > 编程日记 > 正文

[iOS]如何重新架构 JPVideoPlayer ?


注意:此文为配合 JPVideoPlayer version 2.0 版本发布而写,如果你想了解 2.0 版本的更新内容和所有实现细节,请点击前往 GitHub。

导言:我几个月前写了一个在 UITableView 中滑动 UITableViewCell 播放视频的框架,类似于“新浪微博” 和 “Facebook” 首页视频播放。我也为第一版本的 JPVideoPlayer 实现写了两篇文章:
01、[iOS]仿微博视频边下边播之封装播放器 讲述如何封装一个实现了边下边播并且缓存的视频播放器。
02、[iOS]仿微博视频边下边播之滑动TableView自动播放 讲述如何实现在UITableView中滑动播放视频,并且是流畅,不阻塞线程,没有任何卡顿的实现滑动播放视频。同时也将讲述当UITableView滚动时,以什么样的策略,来确定究竟哪一个cell应该播放视频。

当时匆忙实现功能,没有仔细斟酌架构的问题,也没有彻底的实现单个功能的组件化。而且由于架构设计不足带来一些不可避免的问题。这些问题,1.0 版本的用户应该有所体会。前段时间独自回了一趟老家,车程比较长,而且可以专注而不被打扰,在车上写了一个 2.0 版本。2.0 版本有部分内容模仿了SDWebImage 的设计。

2.0 版本效果如下:

01.JPVideoPlayer Version 2.0 如何使用?

考虑到 API 和架构都重新设计了,尤其是 API 全部重新设计,1.0 版本的 API 已经不能沿用了,机智的我已经做好了被骂得很惨的心理准备了。

如果你是新的用户,就不会受之前版本的影响。最终不管你是新用户还是老用户,你一定会喜欢这种新的 API 设计的,因为这是目前 iOS 最受欢迎的 API 设计。

Objective-C:#import <UIView+WebVideoCache.h>...
NSURL *url = [NSURL URLWithString:@"http://lavaweb-10015286.video.myqcloud.com/%E5%B0%BD%E6%83%85LAVA.mp4"];
[aview jp_playVideoWithURL:url];

02.JPVideoPlayer Version 2.0 内部运行细节?

很多用户可能不会有时间去读源码,但是也许会关心 2.0 版本内部实现的一些大的方式,所以这里我总结了一张 2.0 版本的实现大致结构图表,如下:


下面我用文字来表述一下框架内部的运作顺序:

  • 01.提供给外部调用的 API 非常简洁,采用为 UIView 添加分类方法的形式为外界调用,只要导入了头文件,所有 UIView 的子类都拥有播放视频的方法。框架把 UIView的分类方法作为和框架内部交互的桥梁。

  • 02.JPVideoPlayerManager 负责甄别用户传过来的 URL,根据不同的 URL 作出不同的反应进行视频播放。具体细节如下:

    • 02.1、是否是本地文件路径,如果是本地路径,直接把路径给负责视频播放的工具类 JPVideoPlayerPlayVideoTool 进行视频播放;

    • 02.2、如果不是本地路径,再根据 URL 生成缓存的 key 给 JPVideoPlayerCache 工具类查找是否有本地缓存文件,如果有缓存就把缓存路径返还给JPVideoPlayerManagerJPVideoPlayerManager 会把路径给负责视频播放的工具类 JPVideoPlayerPlayVideoTool 进行视频播放;

    • 02.3、如果没有本地缓存,就把 URL 给 JPVideoPlayerDownloader 下载工具类,这个工具类就会去网络上下载视频数据,每下载完一段数据,都会返回给 JPVideoPlayerManagerJPVideoPlayerManager 会先把这段数据给 JPVideoPlayerCache, JPVideoPlayerCache 先把数据缓存到磁盘,然后再把缓存的路径返还给JPVideoPlayerManagerJPVideoPlayerManager 会把路径给负责视频播放的工具类 JPVideoPlayerPlayVideoTool 进行视频播放。

03. JPVideoPlayer Version 2.0 更新了哪些内容?

类名功能点
JPVideoPlayerDownloaderOperation下载单个视频文件工具
JPVideoPlayerDownloader下载工具类,管理下载操作队列
JPVideoPlayerCachePathTool管理临时和完整视频存储路径
JPVideoPlayerCacheConfig缓存配置文件,包括缓存周期,最大磁盘缓存等
JPVideoPlayerCache缓存工具类,负责视频数据的存、取、删、更新
JPVideoPlayerResourceLoader视频播放器的数据代理,负责将网络视频数据填充给播放器
JPVideoPlayerPlayVideoTool视频播放工具类
JPVideoPlayerManager管理者,协调各个模块相互配合工作

接下来我将大致描述一下每个类的实现:

  • 01.JPVideoPlayerDownloaderOperation:它继承自 NSOperation,它内部持有一个 NSURLSession 实例对象,由这个实例对象去负责下载视频数据,JPVideoPlayerDownloaderOperation 成为这个实例对象的代理,监听获取下载到的数据,并将获得的数据回传给操作的所有者 JPVideoPlayerDownloader

  • 02.JPVideoPlayerDownloader:它持有一个下载队列,下载队列里存放的是 JPVideoPlayerDownloaderOperation 实例对象。考虑到播放视频数据量较大而且是持续的,为了将所有的网络资源用于加载当前用户播放的视频,提升使用体验,所以这个队列在任何时候都只允许一个下载操作运行。它接收到 JPVideoPlayerDownloaderOperation 回调的数据以后会继续把数据回传出去。

  • 03.JPVideoPlayerCachePathTool:它负责管理缓存文件的路径,包括临时和完整视频存储路径两个部分。

  • 04.JPVideoPlayerCacheConfig:这个类存放着缓存存储周期,最大磁盘缓存等缓存配置数据。

  • 05.JPVideoPlayerCache:它负责数据的存、取、删、更新等功能。当调用存数据的功能时,会在临时文件存放的文件夹内新建一个 mp4 文件,并开始将数据写入到这个文件内,存完一段数据以后,会将存储数据的路径回调出去。每次播放视频的时候,都会去查询缓存中有没有这个 URL 的完整数据缓存,如果有就会把路径回调出去。它还对外提供获取缓存大小的功能,如果你需要在设置里获取当前视频缓存,可以调用这个接口。它还有删除缓存视频数据的功能。

  • 06.JPVideoPlayerResourceLoader 这个类沿用自 1.0 版本,负责从已经下载的数据中找出播放器需要的数据,并将数据填充到播放器的数据请求中进行视频播放。

  • 07.JPVideoPlayerPlayVideoTool 这个类持有一个视频播放器,负责串联从视频数据到图像和影音的整个播放功能。

  • 08.JPVideoPlayerManager 它是框架的管理者、大管家,它的具体功能上面“内部细节”已经陈述过了,这里不重复了。

  • 09.其他还有一个数据加载进度条和一个缓冲状态指示器,这些都很简单。还有就是 2.0 版本的 Demo 将 UITableViewController 视频播放抽到一个分类中集中管理,也方便后期维护,如果你的需求和 Demo 类似,可以考虑直接把这个分类拽进项目,需要改动的代码很少,就能实现。

04.为什么要这么改?

这个问题我想从用户和我自己,还有它本来应该是什么样子这些维度来分析。

04.1、用户角度
  • 01.首先,受用户欢迎的框架应该要具备两个基本的素质。第一,调用起来方便,能一行代码解决的,绝不搞两行。第二,不侵入用户的项目,万一哪天框架不维护了,也不要成为用户的累赘。

  • 02.其次,我说一个我今天看一个框架的感受,是一个类似微信选择多张照片的框架,框架对外提供的接口不够我用,所以我只能去框架内部改,但是当我找一个功能的时候,框架文档没有说明,我在那些代码应该放的位置也没有找到,需求就是改字体和颜色,我找了一上午,终于在一个不可能猜到的位置找到了那几行代码。这里就有几个问题点:

    • 我们对外提供的接口尽量让使用者够用,如果没有考虑到,那用户就可能会来框架里改。
    • 我们的框架类的命名,方法的命名都应该遵守苹果的那套标准,因为大家天天在用的都是苹果 API,如果完全不遵守苹果那套,那用户来到框架里就是一头雾水,这里有一个沟通成本的问题,看懂代码之前还要先熟悉我们特有的标准。就像去美国,要和美国人说话,要先学英语。
    • 文档一定要详实,每个人水平都不一样,代码可能看不懂,但是文字谁都认识,这是作者和用户沟通的基础。
04.2、作者角度

维护框架其实也是很花时间的一件事情,1.0 版本的时候,就经常有用户给我留言,发QQ消息和我沟通实现的细节,还要他们希望下个版本希望加进去的一些功能。

当时很多功能的代码都混在一个类里,第一就是这个类上千行代码,我自己要改一个东西都需要用搜索功能才能找到,各个方法之间相互调用的时候跳来跳去,头晕眼花。

现在每个模块划分完功能以后,每个功能的核心代码都高度集中在对应的类里,隐藏实现的细节,屏蔽了外部的干扰,只对外提供必要的接口。现在调试问题的时候,分析到出现问题可能的模块以后,能快速定位到对应类的对应方法里,只需要在当前类里专注当前的问题就可以了,不需要考虑外部的影响。这个效率的提升还是蛮明显的。

所以从作者的角度,这个架构的好处就是,第一,方便我后期的维护,提高效率;第二,方便和用户的沟通,减少沟通成本;第三,当有新功能的时候,我能快速的把代码写到对应的类别里。

04.3、它本来的样子

前段时间看 BBC 的 “Planet Earth” 纪录片,里面说蚂蚁巢穴里有几千万只蚂蚁,但是却分工明确,秩序尽然。原来,蚂蚁分为四类:

  • 蚁后,也叫蚁皇,是一族之主,专管产卵繁殖,一般一群只有一个,体型特大,行动不便,由工蚁侍候。
  • 雄蚁,专与蚁后交配,交配后即死亡,一群中有数十只或数百只,要看蚁群的大小。
  • 工蚁,是蚁群中的主要成员,专司觅食、饲养幼蚁、侍候蚁后、搬家清扫等等杂勤工作。
  • 兵蚁,个头较大,双颚发达,是蚁群中的保卫者,担负着本蚁群的安全,如有外蚁入侵,或争夺食物时,必誓死决斗。

我们的代码或许也可以仿照大自然,先划分功能,再列出几个类,将功能点挨个集中到类里,武装出类,就是所谓的对象。这就是我理解的框架应该有的美。

我的文章集合

下面这个链接是我所有文章的一个集合目录。这些文章凡是涉及实现的,每篇文章中都有 Github 地址,Github 上都有源码。如果某篇文章刚好在你的实际开发中帮到你,又或者提供一种不同的实现思路,让你觉得有用,那就看看这句话 “坚持每天点赞的人,99%都是帅哥美女,再也不用单身了”

我的文章集合索引

你还可以关注我自己维护的简书专题 iOS开发心得。这个专题的文章都是实打实的干货。
如果你有问题,除了在文章最后留言,还可以在微博 @盼盼_HKbuy上给我留言,以及访问我的 Github。

相关文章:

函数项目一个超感人的故事:关于swfupload在某些环境下面session丢失的完美解决方案(看完我哭了)...

查了好多资料&#xff0c;发现还是不全&#xff0c;干脆自己整理吧&#xff0c;至少保证在我的做法正确的&#xff0c;以免误导读者&#xff0c;也是给自己做个记录吧&#xff01; 标题吸引到你了吗&#xff1f; 先说一下这个题问成形的原因。大家都晓得 session是靠cookie中的…

【学习笔记】git 使用文档

安装 git # mac 环境 brew install git检查是否安装成功 ➜ ~ git --version git version 2.20.1 (Apple Git-117)卸载 git ➜ ~ which -a git /usr/bin/git ➜ ~ cd /usr/bin ➜ bin sudo rm -rf git*git init 命令 对一个空文件&#xff0c;git 初始化。文件名称增加…

UIBezierPath和CAShapeLayer创建不规则View(Swift 3.0)

最近一个朋友在做图片处理的 App&#xff0c;想要实现类似 MOLDIV App 拼图的UI效果&#xff08;如何创建不规则的 view&#xff09;&#xff0c;就问我有什么想法。我首先想到的就是 UIBezierPathCAShapeLayer的方式&#xff0c;为了验证自己的想法&#xff0c;写了一个小 dem…

http响应状态

Servlet API&#xff1a; javax.servlet.http.HttpServletResponse 用于创建HTTP响应&#xff0c;包括HTTP协议的状态行、响应头以及消息体 HTTP状态码&#xff1a; 100-199&#xff1a;表示信息性代码&#xff0c;标示客户端应该采取的其他动作&#xff0c;请求正在进行。 200…

antlr.collections.AST.getLine()I问题的起因及解决

在我们的java web 项目中引入hibernate和struts&#xff0c;当我们使用HQL语句进行查询时会报 antlr.collections.AST.getLine()I的错误&#xff0c;导致程序无法继续运行&#xff0c;这并不是我们的程序写的有错误&#xff0c;出现这个异常的原因是因为我们使用的hibernate和s…

2018湖湘杯海选复赛Writeup

2018湖湘杯Writeup0x01 签到题0x02 MISC Flow0x03 WEB Code Check0x04 WEB Readflag0x05 WEB XmeO0x06 Reverse Replace0x07 MISC Disk0x08 Crypto Common Crypto0x09 Reverse HighwayHash640x10 Web Mynot0x01 签到题 关注合天智汇公众号&#xff0c;回复hxb2018得到flag。0x…

Operation Queues并发编程

并发、异步在我们的编程中&#xff0c;见到的太多了。在iOS中&#xff0c;实现并发的主要三个途径Operation Queues、Dispatch Queues、Dispatch Sources&#xff0c;今天我们就来详细介绍Operatin Queues的使用&#xff0c;花了两天时间写这一篇&#xff0c;值得一看。 为什么…

socket 服务器浏览器与服务器客户端实例

一、服务器与浏览器 // 取得本机的loopback网络地址&#xff0c;即127.0.0.1 IPAddress address IPAddress.Loopback; IPEndPoint endPoint new IPEndPoint(address, 49152); Socket socket new Socket(AddressFamily.InterNetwork, Socke…

匹配3位或4位区号的电话号码,其中区号可以用小括号括起来,也可以不用,区号与本地号间可以用连字号或空格间隔,也可以没有间隔...

public bool IsPhone(string input){string pattern "^\\(0\\d{2}\\)[- ]?\\d{8}$|^0\\d{2}[- ]?\\d{8}$|^\\(0\\d{3}\\)[- ]?\\d{7}$|^0\\d{3}[- ]?\\d{7}$";Regex regex new Regex(pattern);return regex.IsMatch(input);} 转载于:https://www.cnblogs.com/…

Mac MySQL配置环境变量的两种方法

第一种&#xff1a; 1.打开终端,输入&#xff1a; cd ~ 会进入~文件夹 2.然后输入&#xff1a;touch .bash_profile 回车执行后&#xff0c; 3.再输入&#xff1a;open -e .bash_profile 会在TextEdit中打开这个文件&#xff08;如果以前没有配置过环境变量&#xff0c;那么这…

linux之x86裁剪移植---字符界面sdl开发入门

linux下有没有TurboC2.0那样的画点、线、圆的图形函数库&#xff0c;有没有grapihcs.h&#xff0c;或者与之相对应或相似的函数库是什么&#xff1f;有没有DirectX这样的游戏开发库&#xff1f;SDL就是其中之一。SDL&#xff08;Simple DirectMedia Layer&#xff09;是一个夸平…

iOS 视频捕获系列Swift之AVFoundation(一)

iOS 视频捕获系列之AVFoundation(一) AVCaptureMovieFileOutput系列 在iOS开发过程中&#xff0c;或多或少的都涉及视频的操作。 尤其在去年直播行业的带动下&#xff0c;移动端对视频的处理也愈来愈发要求严格。 本文也是在 这篇 中参考而来。 Swift 版本哦&#xff01; 本文 …

C#做外挂常用API

using System; using System.Collections.Generic; using System.Text; using System.Runtime.InteropServices; //这个肯定要的 namespace WindowsApplication1 {class win32API{public const int OPEN_PROCESS_ALL 2035711;public const int PAGE_READWRITE 4;public con…

phpinfo 信息利用

0x01 基础信息 1.system info:提供详细的操作系统信息&#xff0c;为提权做准备。 2.extension_dir:php扩展的路径 3.$_SERVER[‘HTTP_HOST’]:网站真实IP、CDN什么的都不存在的&#xff0c;找到真实ip&#xff0c;扫一扫旁站&#xff0c;没准就拿下几个站。 4.$_SERVER[‘…

iOS三种录制视频方式详细对比

先附上参考资料 http://www.jianshu.com/p/16cb14f53933 https://developer.apple.com/library/content/samplecode/AVSimpleEditoriOS/Introduction/Intro.html https://github.com/objcio/VideoCaptureDemo https://github.com/gsixxxx/DTSmallVideo https://github.com/Andy…

C# 实现Oracle中的数据与Excel之间的转换

最近项目要求实现数据库之间数据在各个数据库之间导入导出&#xff0c;在此做个笔记 1. 将Oracle中的表导入到Excel中&#xff0c;反之亦然 private static readonly string connectionString ConfigurationManager.ConnectionStrings["OracleConnection"].Connecti…

【转】Word2007中不连续页码设置 多种页码设置

【转】Word2007中不连续页码设置 多种页码设置 页码是论文必不可少的部分。我们看一下如何添加页码&#xff0c;并且针对一些特殊的格式要求怎么应对&#xff1a; 如果是【毕业论文】有多种混合页码&#xff0c;有Ⅰ、Ⅱ、Ⅲ。。。还有1、2、3 。。。请直接看【第二种方法】。 …

vim编辑器异常退出产生备份文件

当非正常关闭vim编辑器时&#xff08;比如直接关闭终端或者电脑断电&#xff09;&#xff0c;会生成一个.swp文件&#xff0c;这个文件是一个临时交换文件&#xff0c;用来备份缓冲区中的内容。 需要注意的是如果你并没有对文件进行修改&#xff0c;而只是读取文件&#xff0c…

从0到1思考与实现iOS-Widget

讲述之前首先看下demo效果图&#xff1a; 基本的展开收起、本App本体交互然后再展示几个效果不错的 Widget app 毒物 && KeepESPNPCalcMusixmatchFantastical 2Carrot Weatherdemo 地址在此&#xff01;欢迎star 比心一、Widget总览 Widget 是 iOS8 推出第一版&…

Android Studio 初体验

Google在I/O2013大会上发布了Android新的开发工具Android Studio&#xff0c;趁周末时间做了一下尝试。有需要的可以在http://developer.android.com/sdk/installing/studio.html下载&#xff0c;当前版本是V0.1。官方解释&#xff1a;Android Studio is anew Android developm…

JAVA面试题(2)

1 String 与 new 的不同 使用“”赋值不一定每次都创建一个新的字符串&#xff0c;而是从“字符串实例池”中查找字符串。使用“new”进行赋值&#xff0c;则每次都创建一个新的字符串。 2 String与StringBuffer String类是不可变类&#xff0c;字符串一旦初始化后&#xff0c…

限制HTTP数据包发送Referer

一般点击一个A标签的时候都会发送 Referer 什么是 Referer&#xff1f; 就是你点击A标签 Referer的信息告诉服务端你从哪里点击出来的 可在HTML上加 <meta name"referrer" content"no-referrer">这样就不发送Referer头了

TCP/IP详解学习笔记(3)-IP协议,ARP协议,RARP协议

把这三个协议放到一起学习是因为这三个协议处于同一层&#xff0c;ARP协议用来找到目标主机的Ethernet网卡Mac地址&#xff0c;IP则承载要发送的消息。数据链路层可以从ARP得到数据的传送信息&#xff0c;而从IP得到要传输的数据信息。 1.IP协议 IP协议是TCP/IP协议的核心&…

数据结构与算法分析(C++版)(第二版)

查看书籍详细信息&#xff1a; 数据结构与算法分析&#xff08;C版&#xff09;&#xff08;第二版&#xff09; 内容简介 本书采用程序员最爱用的面向对象C语言来描述数据结构和算法&#xff0c;并把数据结构原理和算法分析技术有机地结合在一起&#xff0c;系统介绍了各种…

nginx反向代理原理讲解

一 、概述 反向代理&#xff08;Reverse Proxy&#xff09;方式是指以代理服务器来接受Internet上的连接请求&#xff0c;然后将请求转发给内部网络上的服务器&#xff1b;并将从服务器上得到的结果返回给Internet上请求连接的客户端&#xff0c;此时代理服务…

cojs 简单的数位DP 题解报告

首先这道题真的是个数位DP 我们考虑所有的限制&#xff1a; 首先第六个限制和第二个限制是重复的&#xff0c;保留第二个限制即可 第五个限制在转移中可以判断&#xff0c;不用放在状态里 对于第一个限制&#xff0c;我们可以增加一维表示余数即可 对于第四个限制也是同理 对于…

iOS ERROR ITMS - 打包上传报错整理

作者 Silence_广 关注 2017.03.24 11:12 字数 706 阅读 45评论 1喜欢 12ERROR ITMS-90034 ERROR ITMS-90034这个问题就是你的包里面的证书和开发者中心的证书不一样所以提交的时候回报错. 如果试过网上很多的解决方法之后&#xff08;诸如重新制作证书&#xff0c;删调过期证书…

照片墙瀑布流加载与阻止加载

网上大部分主流的瀑布流应用基本都是由后端在提供图片地址的同时提供图片宽高&#xff0c;这样&#xff0c;前端不必等待图片渲染完成&#xff0c;可以根据图片的宽高先把装载图片的容器或父节点先放上页面&#xff0c;完成基础性的布局&#xff0c;再让图片以渐变或其他方式逐…

利用Nginx实现简易负载均衡

基本思路如下&#xff1a; 比如我们有三个服务器&#xff1a; 其中: 130.251是反向代理转发服务器 130.251和130.238分别是负载服务器 Mysql服务器没有标出来, 为方便区分,我们先把1号负载的首页写成111111111 2号负载的首页写成222222 然后我们现在控制130.251, 把nginx配置文…

两行代码搞定iOS自定义HUD风格动画弹窗(支持选择记录) - SKChoosePopView的使用和实现思路

作者 ShevaKuilin 关注 2017.03.25 18:28* 字数 2014 阅读 270评论 0喜欢 23さらい屋五葉原文地址----> MyBlog HUD风格的选项弹窗是我们在日常开发中经常会碰到的一类需求&#xff0c;通常因为项目周期等因素&#xff0c;很少会专门抽出时间来对此类弹窗进行专门的定制开发…