惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

S
Securelist
SecWiki News
SecWiki News
Help Net Security
Help Net Security
Attack and Defense Labs
Attack and Defense Labs
L
LINUX DO - 最新话题
H
Heimdal Security Blog
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
H
Hacker News: Front Page
Hacker News - Newest:
Hacker News - Newest: "LLM"
Google DeepMind News
Google DeepMind News
V2EX - 技术
V2EX - 技术
Hacker News: Ask HN
Hacker News: Ask HN
O
OpenAI News
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
T
Threat Research - Cisco Blogs
A
Arctic Wolf
Simon Willison's Weblog
Simon Willison's Weblog
P
Privacy & Cybersecurity Law Blog
T
Threatpost
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
C
Cyber Attacks, Cyber Crime and Cyber Security
T
Tor Project blog
C
CXSECURITY Database RSS Feed - CXSecurity.com
Spread Privacy
Spread Privacy
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
人人都是产品经理
人人都是产品经理
S
SegmentFault 最新的问题
www.infosecurity-magazine.com
www.infosecurity-magazine.com
P
Palo Alto Networks Blog
C
CERT Recently Published Vulnerability Notes
PCI Perspectives
PCI Perspectives
AWS News Blog
AWS News Blog
IT之家
IT之家
美团技术团队
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
T
Tailwind CSS Blog
M
MIT News - Artificial intelligence
V
Visual Studio Blog
Schneier on Security
Schneier on Security
T
The Exploit Database - CXSecurity.com
有赞技术团队
有赞技术团队
小众软件
小众软件
Google Online Security Blog
Google Online Security Blog
N
News | PayPal Newsroom
博客园_首页
T
Tenable Blog
酷 壳 – CoolShell
酷 壳 – CoolShell
S
Secure Thoughts
I
Intezer

音视频开发进阶

音视频教程-第三节 音视频教程-第二节 真的,AI 可能就是新时代的信息差 充值 Cursor 之后,工作有了哪些变化?🤔 个人'蒸馏'大模型能做哪些有意思的事情 DeepSeek 大模型在 Mac 上的部署和运行 音视频教程-第一节 【WebRTC 专栏】-- Android 开发集成 WebRTC 库的几种方式 【WebRTC 专栏】-- 在 Mac M1 等系列芯片编译和开发 WebRTC-Android 库 Meta Llama3 大模型在 Mac 上的部署和运行 iOS VideoToolBox 解码 HEVC Open-GOP 视频的问题排查 Flutter 状态管理之 InheritedWidget 使用和分析 用 ChatGPT 回答技术问题怎么样 ? 音视频开发系统入门大致路线 UE 4.27 添加自定义 ShadingModel 用 UE4 虚幻引擎做个捏脸小功能~~ UE4 材质练习 之 凹凸贴图偏移的使用 UE4 材质练习系列基础 OpenGL上下文创建以及共享机制 007 | 播放器系列专栏-解析 MP4 文件读取信息 006 | 播放器系列专栏-在 Mac 上查看 MP4 格式信息 干货 | 快速抽取缩略图是怎么练成的? 关于直播、WebRTC、FFmpeg 的那些事 005 | 播放器系列专栏-在 Windows 上查看 MP4 格式信息 将音视频中的花屏、绿屏、黑屏问题一网打尽 关于音视频里面的解码帧率和渲染帧率 004 | 播放器系列专栏-认识MP4视频(下) 003 | 播放器系列专栏-认识MP4视频(上) 入门或者转行音视频,应该要怎么做? H264视频文件如何缩放分辨率 002 | 播放器系列专栏-FFmpeg依赖库的配置 001 | 播放器系列专栏-关于播放器项目的一个小实践 Seek策略以及在有B帧情况下的处理 目前流媒体开发工程师工作内容主要是什么? 一个音视频领域专业问答的小圈子 干货收藏 || Vulkan Game Engine 视频教程 音视频春节假期内卷指南(实操) Vulkan 在 FFmpeg 中的支持 Windows 下 FFmpeg 和 LibX264 的编译和配置 Metal 开发 | 使用 C++ 进行接口调用 音视频开发工作经验分享 || 视频版 FFmpeg 调用 MediaCodec 硬解码到 Surface 上 代码吸猫 | 用 OpenGL 图像渲染的养猫计划 百倍变速--解码到底能不能丢 非参考帧 ?FFmpeg 有话说!!! 老生常谈-FFmpeg 的编译问题轻松搞定 FFmpeg 调用 Android MediaCodec 进行硬解码(附源码) 【WebRTC 专栏】--创建相机预览 Unity Shader 光照基础之 Half Lambert 光照模型 Unity Shader 光照基础之Lambert光照模型 Unity Shader 光照基础内容 Unity Shader 显示一张图片纹理 UnityShader 的基本概念 Unity 物体的基本操作 C++ 模板系列小结07-尾置返回类型 C++ 模板系列小结06-可变参数模板特性 C++ 中的多线程的使用和线程池建设 C++ 模板系列小结05-模板类型作为模板参数 C++ 模板系列小结04-类模板中的成员模板 C++ 模板系列小结03-在模板中指定变量类型 C++ 模板系列小结02-非类型模板参数 C++ 模板系列小结01-函数模板和类模板 从零打造渲染引擎系列01-什么是渲染引擎 iOS开发 - 在 Swift 中去调用 C/C++ 代码 2021 技术新番 - 从零打造渲染引擎系列 音视频交流群又来啦~~~ 【WebRTC 专栏】WebRTC & Android 开发学习环境搭建~ 【喜大普奔】域名终于备案通过啦 Shader 优化 | OpenGL 绘制网格效果 【音视频连载-011】第二季 FFmpeg 一层一层获取文件信息 KodeLife | Shader 实时编辑预览的强大工具使用实践 推荐几个堪称教科书级别的 Android 音视频入门项目 【音视频连载-010】第二季 FFmpeg 日志打印 【音视频连载-008】基础学习篇-SDL 播放 PCM 音频文件(下) 【音视频连载-007】基础学习篇-SDL 播放 PCM 音频文件(上) 【音视频连载-006】基础学习篇-SDL 播放 YUV 视频文件 【音视频连载-005】基础学习篇-SDL 加载 YUV 文件并显示 【音视频连载-004】基础学习篇-SDL 加载图片并显示 【音视频连载-003】基础学习篇-SDL 消息循环和事件响应 【音视频连载-002】基础学习篇-SDL 创建窗口并显示颜色 【音视频连载-001】基础学习篇- SDL 介绍以及工程配置 LearnOpenGL 源码在 MAC 上的编译与调试 2019 年终总结与回顾 Android NDK 开发的免费技术视频来啦~~ OpenGL 实现视频编辑中的转场效果 OpenGL 实践之贝塞尔曲线绘制 图像库 libjpeg-turbo 编译与实践 图像库 libpng 编译与实践 rust 开发编译 Android 动态库实践 Android NDK 开发 —— 从 Assets 文件夹加载图片并上传纹理 简单易用的图像解码库介绍 —— stb_image 博客图床迁移记 进击的 Vulkan 移动开发之 SwapChain 进击的 Vulkan 移动开发之 Command Buffer 进击的 Vulkan 移动开发之 Instance & Device & Queue 进击的 Vulkan 移动开发(一)之今生前世 Java 显式锁 Lock 与条件队列 C++ 标准容器库小结 MediaCodec 硬编码之相机内容编码成 H264 文件 一文读懂 YUV 的采样与格式 《OpenGL ES 3.x 游戏开发》碰撞检测之 AABB 包围盒
iOS 音视频开发的一些基础准备工作
音视频开发进阶 · 2020-11-17 · via 音视频开发进阶

一个专注音视频领域的小圈子

最近在捣鼓 iOS 上的音视频开发,由于之前并没有 iOS 开发经验,直接上手写代码的话压力还是挺大的,因此也趁机看了下 iOS 开发的内容,算是做一些准备工作吧。 iOS 开发语言用的是 Swift ,一些语法和 Kotlin 还是挺像的,上手难道小了很多,而且也实在受不了 OC 的中括号 [] 调用方式,写不习惯。

在应用开发上,新手入门当然就是学习调用各种控件了。像 Button、Label 这样的单控件都还比较简单,看看就会。像 UITableView、UINavigationViewController 这些复合控件就相对复杂了,需要实际练练手才行,包括 XCode、StoryBoard 等工具的使用,也需要有一定的熟练度才好。这也是本篇文章的主要目的了,通过博客记录的形式来提高熟练度。

基础准备工作就先从界面编程开始吧,能折腾出一个简单的应用。至于更深层次的 iOS 应用生命周期、性能优化、图形图像那些就等后面碰到了再研究吧。

iOS 应用创建和移除 SceneDelegate

当前使用的 XCode 版本是 12.1 ,创建 iOS 应用默认使用了 SceneDelegate ,这里用不上它,先把它移除了。

步骤如下:

  • 删除 SceneDelegate.swift 文件
  • 在 Info.plist 文件里面移除 Application Scene Manifest
  • 删除 AppDelegate.Swift 中的 connectingSceneSession 和 didDiscardSceneSessions 方法。
  • 在 AppDelegate.swift 中添加 UIWindow 变量。
@main
class AppDelegate: UIResponder, UIApplicationDelegate {

    var window: UIWindow?

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        // Override point for customization after application launch.
        return true
    }

}

UITableView 的使用

从 UITableView 开始搞起。在默认的 Main.storyboard 对应的 ViewController 里面添加一个 UITableView 类。

然后通过 Auto Layout 将它铺满整个应用,这个时候启动应用的话会显示黑屏的,因为没有给它填充数据。

UITableView 通过 UITableViewDataSource 和 UITableViewDelegate 分别来控制它的数据和交互逻辑。

其中 UITableViewDataSource 有如下方法是必现要实现的,指定要展示的数据内容和 TableView 中 Item ,而 UITableViewDelegate 就没强制要求实现方法了,至于协议中的其他方法都可以查看具体源码,有具体的应用场景再使用了。

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        <#code#>
}  

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        <#code#>
}

通过 extension 语法来实现以上两个协议:

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return 100;
}

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: "reuse", for: indexPath)
    cell.textLabel?.text = "hello tableview"
    return cell
}

这里要指定 StoryBoard 中的 UITableView 对应单元格的 Identifer ,它代表了 TableView 中单元格的复用标识,dequeueReusableCell 方法就是通过这个字符串标识来复用的。

TableView 的复用逻辑类似于 Android 中的 RecyclerView 了,都是复用移出屏幕外的单元格来节省内存的。

最后在 StoryBoard 中将 UITableView 与 ViewController 建立起关联,并给 UITableView 指定具体协议的实现。

    @IBOutlet weak var mTableView: UITableView!
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
        mTableView.dataSource = self
        mTableView.delegate = self
    }

这个时候再启动应用就能看到 TableView 中充满内容了。

当然,这里也省略了很多内容。比如自定义单元格样式、通过代码来添加 UITableView 等。

UITableView 跳转详情页和返回

在实现了 UITableView 的基础上,继续开发实现点击某个单元格跳转到详情页并返回的功能。

在 Main.storyboard 中添加一个 ViewController ,并添加一个 Label,一个 Button,分别展示内容和返回。

完成详情页的展示如下:

接下来要实现 UITableView 到详情页的跳转,通过 Segue 的方式进行连接。

Segue 使用

iOS 实现页面跳转有多种方式,比如 UINavigationController、UITarBarController 等控制器,或者在 StoryBoard 上进行连线。

Segue 跳转到详情页

连线的方式也比较简单,鼠标点击要连接的控件,然后按住 Control 键拖曳到另一个 ViewController 上,在弹出的 Segue 页面中选择跳转样式。

这里面有多种样式可以选择:

  • Show
  • Show Detail
  • Present Modialy
  • Present As Popover
  • Custom

简单点直接选择了 Show 就行了,连接后的样子如下:

这时候直接运行程序就能在 TableView 中点击某一项跳转到详情页了,接下来就是要从详情页返回到 TableView 界面。

Segue 实现详情页返回

按照上面的逻辑,在详情页的 Back 按键上建立 Segue 就会返回了。但是这样会新建一个 ViewController 而不是返回到之前使用的,来回操作点击的话,不断新建页面,最终导致内存可能暴涨。

这里要用到 Unwind Segue 方法了。在 DetailViewController 中添加如下方法:

@IBAction func unwindSegue(segue: UIStoryboardSegue) {
    NSLog("Back to Table View Controller!")
}

然后,点击详情页的 Back 按键,再按住 Control 键拖曳到 TableView 对应 ViewController 的 Exit 方法处,会弹出上面写的 unwindSegue 方法,点击该方法即可建立连接。

这时候再运行应用,就能实现 TableView 到详情页的跳转了,点击 Back 按键返回到 TableView 界面,输出上面的 log 内容,并且不建立新的 ViewController 。

Segue 数据传递

当想在 ViewController 之间传递数据的话,也可以通过 Segue 进行,它提供了一些方法。

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(nullable id)sender API_AVAILABLE(ios(5.0));

通过实现 prepareForSegue 方法达到数据传输的目的。

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    if segue.identifier == "toDetailView" {
        let cv = segue.destination as! DetailViewController
        cv.str = "data"
    }
}

在 Segue 进行跳转的时候,prepare 方法是必定会执行的,通过实现该方法就能传递数据了。

当然,还有其他的一些方法去传递数据,这里就不阐述了。

UINavigationController 使用

使用 UINavigationController 比较简单,在 Editor 菜单下面的 Embed In 选择 Navigation Controller ,就自动将 TableView 嵌入到 UINavigationController 里面去了。

这时再运行程序就能看到效果了,上层多了一个导航栏。

上层看到的导航栏叫做 NatigationItem ,它有很多属性可以配置,如下图所示:

可以设置左右按键名称和事件,可以设置中间的标题,还可以设置上层的提示内容以及背景颜色。

self.navigationItem.prompt = "loading" 
self.navigationController?.navigationBar.barTintColor = UIColor.yellow;

// 这里的 Button 其实是 UIBarButtionItem,要注意类型
let leftItem = UIBarButtonItem(title: "left", style: UIBarButtonItem.Style.done, target: self, action: #selector(leftAction))        
let rightItem = UIBarButtonItem(title: "right", style: UIBarButtonItem.Style.done, target: self, action: #selector(rightAction))
self.navigationItem.leftBarButtonItem = leftItem
self.navigationItem.rightBarButtonItem = rightItem

self.navigationItem.title = "NavigationItem"

对应的左右按键事件代码如下:

@objc func leftAction(){
    print("click left action")
}
    
@objc func rightAction(){
    print("click right action")
}

这里只是简单地定义了一下样式,还可以弄得更加复杂花哨一点,比如带有图片的 UIBarButtonItem,自定义的 UIBarButtonItem 等。

注意的是,当在 StoryBoard 中嵌入了 UINavigationController 之后,就可以通过 self.navigationController 来引用它了,如果没有嵌入,直接引用会 Crash 的。

在详情页 DetailViewController 中同样能够通过 self.navigationController 来修改 NavigationItem 的样式。

通过 NavigationController 实现页面跳转

除了使用 Segue 之外,还可以使用 NavigationController 来实现页面跳转,先把之前添加的 Segue 移除掉。

NavigationController 是一个管理 UIViewController 的容器,以栈的形式进行管理,提供相应的方法如下:

// 将 ViewController 压入栈中
open func pushViewController(_ viewController: UIViewController, animated: Bool)

// 弹出栈顶的 ViewController
open func popViewController(animated: Bool) -> UIViewController?

// 弹出到指定的 ViewController
open func popToViewController(_ viewController: UIViewController, animated: Bool) -> [UIViewController]?

// 弹出除 root ViewController 之外的所有 ViewController
open func popToRootViewController(animated: Bool) -> [UIViewController]?

// 返回只读属性的栈顶 ViewController
open var topViewController: UIViewController? { get }

// 返回栈中当前可见的界面对应的 ViewController,也是只读属性
open var visibleViewController: UIViewController? { get }

// 返回栈中所有的 ViewController
open var viewControllers: [UIViewController]

实现页面跳转,要做的就是在 TableView 的 Item 点击事件中将详情页的 ViewController 压入栈中,然后在详情页 ViewController 的 Back 事件中进行出栈,把当前 ViewController 弹出栈顶,回到 TableView 界面。

代码如下,在点击事件中进行初始化 ViewController ,并压入栈中。

func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        
    let storyboad = UIStoryboard(name: "Main", bundle: nil)
        
    let vc = storyboad.instantiateViewController(identifier: "detailvc")  as! DetailViewController
    vc.str = "data"
    
    self.navigationController?.pushViewController(vc, animated: false)
}

在 Back 按键的点击事件中进行出栈操作。

@IBAction func back(_ sender: Any) {
    self.navigationController?.popViewController(animated: true)
}

此时再运行代码,同样也能实现页面跳转,并且还传递了数据过去,和使用的 Segue 的效果基本一致。

小结

通过以上简单的小例子,就基本算是了解 iOS 开发了。

内容比较浅显,很多东西还是可以再继续拓展一下的,比如 TableView 中自定义单元格样式、通过代码来加载 NavigationController 等等。不过相信有了上面的基础,再到实践中去学习一些新的技巧也会更加快捷了。

其实 iOS 和 Android 还是有不少相似之处的,毕竟都是移动平台上的应用开发,在一些设计思想有相同之处也不奇怪,比如 TableView 的回收之处、屏幕适配的布局约束等等,这也是要求程序员在学习的时候不仅能够知其然还要知其所以然,学会举一反三,这样再换到其他平台上去学习也能够得心应手,而不是疲于追赶技术。

接下来就是进击 iOS 音视频开发啦~~~

原创文章,转载请注明来源:    iOS 音视频开发的一些基础准备工作