iPhone开发Swift基础03 视频、网络请求

视频播放AVPlayer

iOS9之前使用的是MPMoviePlayerController,随着iOS不断迭代,AVPlayer成为主流。
往项目中添加资源文件:
iPhone开发Swift基础03 视频、网络请求

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)
    }
}

配置画中画

iPhone开发Swift基础03 视频、网络请求

  • 第一步点击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()
    }
}

运行结果:
iPhone开发Swift基础03 视频、网络请求
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."
            }
        }
    }
}

运行结果:
iPhone开发Swift基础03 视频、网络请求

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)")
        }
    }
}

运行结果:
iPhone开发Swift基础03 视频、网络请求
由于学习的这本教材所支持的服务器已经没有提供相应的反应,无法确认,以后有其他的网站示例再更新吧。

使用Alamofire上传图片

当使用JSON或URL编码参数向服务器发送较少数据的时候,Alamofire的request方法是够用的,但是面对上传图片或者其他大文件的时候就需要用到Alamofire的upload方法了。

首先往项目中导入示例资源文件wind.png
iPhone开发Swift基础03 视频、网络请求

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的方式:
iPhone开发Swift基础03 视频、网络请求

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!)
    }
}

运行结果:
iPhone开发Swift基础03 视频、网络请求

使用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

运行结果;
iPhone开发Swift基础03 视频、网络请求

上一篇:SpringBoot 基础10 Elasticsearch


下一篇:基于java处理ofd格式文件