视频播放AVPlayer
iOS9之前使用的是MPMoviePlayerController,随着iOS不断迭代,AVPlayer成为主流。
往项目中添加资源文件:
import UIKit
import AVFoundation
class ViewController: UIViewController{
var avPlayer : AVPlayer?
override func viewDidLoad() {
super.viewDidLoad()
let mp4url = Bundle.main.path(forResource: "apple", ofType: "mp4")
let movieURL = URL(fileURLWithPath: mp4url!)
avPlayer = AVPlayer(url: movieURL)
let avPlayerLayer = AVPlayerLayer(player: avPlayer)
avPlayerLayer.frame = self.view.frame
avPlayerLayer.videoGravity = AVLayerVideoGravity.resizeAspectFill
self.view.layer.addSublayer(avPlayerLayer)
avPlayer?.play()
}
}
videoGravity属性类型:
- AVLayerVideoGravity.resizeAspectFill 保留宽高比,填满屏幕
- AVLayerVideoGravity.resizeAspect 显示范围内缩放视频大小,保持宽高比
- AVLayerVideoGravity.resize 拉伸视频来匹配显示区域
AVPlayerViewController
使用AVPlayerViewController需要再import AVKit
import UIKit
import AVFoundation
import AVKit
class ViewController: UIViewController{
override func viewDidLoad() {
super.viewDidLoad()
let mp4url = Bundle.main.path(forResource: "apple", ofType: "mp4")
let movieURL = URL(fileURLWithPath: mp4url!)
let avPlayer = AVPlayer(url: movieURL)
let avPlayerVC = AVPlayerViewController()
avPlayerVC.player = avPlayer
avPlayerVC.videoGravity = AVLayerVideoGravity.resizeAspect
avPlayerVC.allowsPictureInPicturePlayback = true
avPlayerVC.showsPlaybackControls = true
avPlayerVC.view.frame = self.view.bounds
avPlayerVC.player!.play()
self.view.addSubview(avPlayerVC.view)
}
}
配置画中画
- 第一步点击Capabilities
- 第二步点击增加Capabilities - Background Modes
- 第三步点击Audio AirPlay and Picture in Picture
网络请求
HTTP定义了与服务器交互的不同方法,其中最基本的有4种:GET、POST、PUT、DELETE。
GET与POST
每个GET与POST都由一系列的HTTP请求头组成,这些请求头定义了客户端想从服务器端请求什么数据。同样,响应是由一系列的应答头和应答数据组成。
GET使用MIME类型application/x-www-form-urlencoded的urlencoded文本格式传递参数。Urlencoding是一种字符编码,保证被传递的参数遵循规范。
POST参数也是被URL编码的,但变量名/变量值不作为URL的一部分被传送,而是放在实际HTTP请求消息内部被传送。
GET是从服务器上获取数据,POST是向服务器发送数据。GET通过URL提交数据,数据可以在URL中看见。POST是将请求数据放在请求头HTML HEADER 内提交的。GET提交的数据最多只能有1024字节,而POST没有这个限制。使用GET的时候,参数会暴露出来而POST不会,因此,GET常用于提交非敏感数据。
在iOS开发中常用URLSession的委托协议来实现不同阶段回调不同的对象方法。
URLSession
使用URLSession进行网络请求
URLSession是一组相互依赖的类,它的绝大部分组件和NSURLConnection中的组件相同。比如,URLRequest、URLCache等等。
URLSession的不同之处在于,它将URLConnection替换为URLSession和URLSessionConfiguration,以及三个URLSessionTask的子类:URLSessionDataTask、URLSessionUploadTask、URLSessionDownloadTask。
使用URLSession可以实现:
- 通过URL下载数据到内存
- 通过URL下载数据到文件系统
- 将数据上传到指定的URL
- 在后台完成上传和下载
- 下载文件具有断点续传的功能
- 后台上传或下载具有任务进度跟踪的功能
class ViewController: UIViewController{
var label : UILabel!
override func viewDidLoad() {
super.viewDidLoad()
label = UILabel(frame: CGRect(x: 0, y: 0, width: 480, height: 568))
label.text = "loading..."
label.font = UIFont(name: "Arial", size: 14)
label.numberOfLines = 0
label.lineBreakMode = NSLineBreakMode.byWordWrapping
self.view.addSubview(label)
let urlString:String = "https://www.baidu.com"
let url:URL!=URL(string: urlString)
let request:URLRequest = URLRequest(url: url)
let session = URLSession.shared
let dataTask = session.dataTask(with: request) { (data, response, error) in
print("有结果了")
if error != nil {
print(error?.localizedDescription)
}else{
//因为URLSession请求是异步进行的,
//所以需要返回主线程更新UI
DispatchQueue.main.async {
let str = NSString(data: data!, encoding: String.Encoding.utf8.rawValue)
self.label.text = str as! String
}
}
}
dataTask.resume()
}
}
运行结果:
let dataTask = session.dataTask(with: request) { (data, response, error) 这一段,只不过是session单例对象声明处理执行的url并在完成后调用尾部闭包的处理的一个过程。但实际上并没有开始执行网络请求,在调用resume()后才开始执行请求任务。
除了请求远程数据以外,URLSession还有上传和下载的功能。使用该功能需要遵循URLSessionDownloadDelegate协议来实现下载进度的监听。
class ViewController: UIViewController, URLSessionDownloadDelegate{
var backgroundView:UIView!
var foregroundView:UIView!
var progressLabel:UILabel!
//初始化URLSession对象,并设置代理为当前的控制器,由控制器实现代理方法来监听图片下载
func getSession() -> Foundation.URLSession {
var session:URLSession? = nil
let config = URLSessionConfiguration.default
session = URLSession(configuration: config, delegate: self, delegateQueue: nil)
return session!
}
//监听图片下载完成的代理方法
func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didFinishDownloadingTo location: URL) {
print("下载完成!")
}
override func viewDidLoad() {
super.viewDidLoad()
backgroundView = UIView(frame: CGRect(x: 50, y: 50, width: 200, height: 40))
backgroundView.backgroundColor = UIColor.lightGray
foregroundView = UIView(frame: CGRect(x: 54, y: 54, width: 0, height: 32))
foregroundView.backgroundColor = UIColor.green
progressLabel = UILabel(frame: CGRect(x: 54, y: 100, width: 200, height: 32))
progressLabel.textAlignment = NSTextAlignment.center
self.view.addSubview(backgroundView)
self.view.addSubview(foregroundView)
self.view.addSubview(progressLabel)
let urlString:String = "https://p8.itc.cn/images01/20210416/0f44703fd5754c24af70ea031fe135b4.png"
let url:URL!=URL(string: urlString)
let request:URLRequest = URLRequest(url: url)
let session = self.getSession() as Foundation.URLSession
let downloadTask = session.downloadTask(with: request)
downloadTask.resume()
}
//监听下载进度的代理方法
func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didWriteData bytesWritten: Int64, totalBytesWritten: Int64, totalBytesExpectedToWrite: Int64) {
let rate:CGFloat = CGFloat(totalBytesWritten)/CGFloat(totalBytesExpectedToWrite)
DispatchQueue.main.async {
self.foregroundView.frame.size.width = rate * 192
if rate == 1.0 {
self.progressLabel.text = "Finished."
}
}
}
}
运行结果:
Alamofire
在OC时代,Alamofire的名字是AFNetworking。
使用Alamofire进行GET请求
在使用前需要先import Alamofire 框架。
Alamofire的使用方式较4.0版本有了较大的不同,比如4.0时期用Alamofire调用类方法的,现在5.0使用AF。
而且在返回值方面也做了较明显的改动。自己阅读,这里给出请求范例
import UIKit
import Alamofire
class ViewController: UIViewController{
override func viewDidLoad() {
super.viewDidLoad()
getInfo()
}
func getInfo() -> () {
let url : String = "https://www.baidu.com/get"
AF.request(url).responseString { (afDataResponseString) in
print(afDataResponseString)
}
}
}
运行结果:
success("<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\n<html><head>\n<title>404 Not Found</title>\n</head><body>\n<h1>Not Found</h1>\n<p>The requested URL /get was not found on this server.</p>\n</body></html>\n")
Alamofire默认是进行GET请求。Alamofire最大的特色就是采用链式请求/响应的方式来进行网络交互,如上述代码所示,请求request与返回体respond都写在一行上。代码量非常少、简洁。
使用Alamofire进行POST请求
import UIKit
import Alamofire
class ViewController: UIViewController{
override func viewDidLoad() {
super.viewDidLoad()
postInfo()
}
func postInfo() -> () {
//声明post的参数类型为键值对都是String的字典类型
var parameters : Dictionary<String,String> = Dictionary()
parameters["email"] = "fzhlee@coolketang.com"
parameters["password"] = "123456"
let url : String = "https://www.coolketang.com/post"
struct DecodableType: Decodable { let url: String }
AF.request(url, method: HTTPMethod.post, parameters: parameters, encoding: URLEncoding.default, headers: nil, interceptor: nil, requestModifier: nil).responseDecodable(of: DecodableType.self) { (dataResponse) in
print("\(dataResponse)")
}
AF.request(url, method: HTTPMethod.post, parameters: parameters, encoding: URLEncoding.default, headers: nil, interceptor: nil, requestModifier: nil).responseString { (dataResponse) in
print("\(dataResponse)")
}
}
}
运行结果:
由于学习的这本教材所支持的服务器已经没有提供相应的反应,无法确认,以后有其他的网站示例再更新吧。
使用Alamofire上传图片
当使用JSON或URL编码参数向服务器发送较少数据的时候,Alamofire的request方法是够用的,但是面对上传图片或者其他大文件的时候就需要用到Alamofire的upload方法了。
首先往项目中导入示例资源文件wind.png
import UIKit
import Alamofire
class ViewController: UIViewController{
override func viewDidLoad() {
super.viewDidLoad()
uploadImage()
}
func uploadImage() -> () {
let imageURL = Bundle.main.url(forResource: "wind", withExtension: "png")
struct DecodableType: Decodable { let url: String }
AF.upload(imageURL!, to: "https://httpbin.org/post").uploadProgress { (progress) in
print("--进度:\(progress.fractionCompleted)")
print("--完成:\(progress.completedUnitCount)")
print("--总量:\(progress.totalUnitCount)")
}.responseDecodable { (dataResponse:DataResponse<DecodableType, AFError>) in
let message = "Result:\(dataResponse.result)"
print(message)
}
}
}
在upload方法中,其第一个参数也可以是Data数据类型,这样就可以将内存中的数据上传到服务器中。
另外在Alamofire请求数据的过程中会收集每个步骤的耗时,并生成一个时间线对象
运行结果:
--进度:0.11106045996139592
--完成:65536
--总量:590093
--进度:1.0
--完成:590093
--总量:590093
Result:success(S1.ViewController.(unknown context at $106e70ce8).(unknown context at $106e70d3c).DecodableType(url: "https://httpbin.org/post"))
在返回体dataResponse中,通过断点逐个查看其中的成员属性,还有一些关于请求、加载、解析等耗时的统计。
AlamofireImage
使用AlamofireImage缓存图片
Alamofire还有一些扩展,AlamofireImage就是其中之一,能够处理图像处理和缓存等方面的拓展。
使用AlamofireImage来进行加载图片时,具有以下特点:
- 使用简单,自动在内存中缓存图片,加载过的图片在没有网络的时候也能显示。
- 包含一些常用的扩展,如压缩、缩放、圆角、滤镜等等。
在使用之前先导入框架,以CocoaPods的方式:
import UIKit
import Alamofire
import AlamofireImage
class ViewController: UIViewController{
var imageView : UIImageView?
override func viewDidLoad() {
super.viewDidLoad()
getImageByAlamofireImage()
}
func getImageByAlamofireImage() -> () {
let image = UIImage(named: "wind.png")!
let imageSize = CGSize(width: 100, height: 100)
//使用AlamofireImage处理图像
let scaleImage = image.af.imageScaled(to: imageSize)
//用图片去初始化imageview,这样imageView的尺寸就会是图片的尺寸
imageView = UIImageView(image: scaleImage)
imageView?.center = self.view.center
self.view.addSubview(imageView!)
}
}
运行结果:
使用AlamofireImage给图片添加滤镜
//使用AlamofireImage处理图像
let blurImage = image.af.imageFiltered(withCoreImageFilter: "CIMotionBlur", parameters: ["inputRadius":5,"inputAngle":45])
imageView = UIImageView(image: blurImage)
imageView?.frame = CGRect(x: 0, y: 0, width: 200, height: 200)
imageView?.center = self.view.center
运行结果;