欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

用Swift实现iOS相机及相册图片上传

程序员文章站 2024-03-23 08:57:52
...

最近要做一个iOS相机及相册图片上传,其中遇到了这些问题:1、图片增删在UICollectionView里的变化;2、获取相机拍摄的照片和相册的照片;3、将PHAsset对象转为UIImage对象;
用Swift实现iOS相机及相册图片上传


具体实现过程:
首先整个控件结构如图所示:
用Swift实现iOS相机及相册图片上传
storyboard长这样:
用Swift实现iOS相机及相册图片上传
拖动三个UIViewController如图所示,其中:AlbumImageCollectionViewController(id为ImageCollectionVC)中拖入一个UICollectionView、一个UIToolBar,UICollectionView中的cell(id为cell)拖入两个UIImageView;AlbumImagePickerViewController(id为imagePickerVC)中拖入一个UITableView,UITableView的cell(id为cell)拖入两个UILabel。


PhotoCollectionViewCell:

import UIKit
// 已选择的图片缩略图cell
class PhotoCollectionViewCell: UICollectionViewCell {
    // 已选择的图片
    var imageView: UIImageView!

    // 删除按钮
    var button = UIButton()

    // MARK: - 初始化方法
    override init(frame: CGRect) {
        super.init(frame: frame)
        // 设置缩略图大小
        imageView = UIImageView(frame: self.bounds)

        // 设置按钮属性
        button = UIButton(type: UIButtonType.custom)
        button.setImage(UIImage.init(named: "delete"), for: UIControlState.normal)
        button.frame = CGRect(x: frame.size.width - 21, y: 1, width: 20, height: 20)

        self.addSubview(imageView)
        self.addSubview(button)
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}

AlbumImagePickerTableViewCell:

import UIKit
// 相簿列表单元格
class AlbumImagePickerTableViewCell: UITableViewCell {

    // 相簿名称标签
    @IBOutlet weak var titleLabel: UILabel!
    // 照片数量标签
    @IBOutlet weak var countLabel: UILabel!

    override func awakeFromNib() {
        super.awakeFromNib()
        self.layoutMargins = UIEdgeInsets.zero
    }

    override func setSelected(_ selected: Bool, animated: Bool) {
        super.setSelected(selected, animated: animated)
    }

}

AlbumImageCollectionViewCell:

import UIKit
// 图片缩略图集合页单元格
class AlbumImageCollectionViewCell: UICollectionViewCell {
    // 显示缩略图
    @IBOutlet weak var imageView: UIImageView!

    // 显示选中状态的图标
    @IBOutlet weak var selectedIcon: UIImageView!

    // 设置是否选中
    open override var isSelected: Bool {
        didSet{
            if isSelected {
                selectedIcon.image = UIImage(named: "image_selected")
            }else{
                selectedIcon.image = UIImage(named: "image_not_selected")
            }
        }
    }

    // 播放动画,是否选中的图标改变时使用
    func playAnimate() {
        // 图标先缩小,再放大
        UIView.animateKeyframes(withDuration: 0.4, delay: 0, options: .allowUserInteraction, animations: {
            UIView.addKeyframe(withRelativeStartTime: 0, relativeDuration: 0.2, animations: {
                self.selectedIcon.transform = CGAffineTransform(scaleX: 0.7, y: 0.7)
            })
            UIView.addKeyframe(withRelativeStartTime: 0.2, relativeDuration: 0.4, animations: {
                self.selectedIcon.transform = CGAffineTransform.identity
            })
        }, completion: nil)
    }

    override func awakeFromNib() {
        super.awakeFromNib()
        imageView.contentMode = .scaleAspectFill
        imageView.clipsToBounds = true
    }
}

AlbumImageCompleteButton:

import UIKit
// 照片选择页下方工具栏的“完成”按钮
class AlbumImageCompleteButton: UIView {
    // 已选照片数量标签
    var numLabel: UILabel!

    // 按钮标题标签“完成”
    var titleLabel: UILabel!

    // 按钮的默认尺寸
    let defaultFrame = CGRect(x: 0, y: 0, width: 70, height: 20)

    // 文字颜色(同时也是数字背景颜色)
    let titleColor = UIColor(red: 0x09/255, green: 0xbb/255, blue: 0x07/255, alpha: 1)

    // 点击点击手势
    var tapSingle: UITapGestureRecognizer?

    // 设置数量
    var num:Int = 0{
        didSet{
            if num == 0{
                numLabel.isHidden = true
            }else{
                numLabel.isHidden = false
                numLabel.text = "\(num)"
                playAnimate()
            }
        }
    }

    //是否可用
    var isEnabled:Bool = true {
        didSet{
            if isEnabled {
                titleLabel.textColor = titleColor
                tapSingle?.isEnabled = true
            }else{
                titleLabel.textColor = UIColor.gray
                tapSingle?.isEnabled = false
            }
        }
    }

    init(){
        super.init(frame:defaultFrame)

        // 已选照片数量标签初始化
        numLabel = UILabel(frame:CGRect(x: 0 , y: 0 , width: 20, height: 20))
        numLabel.backgroundColor = titleColor
        numLabel.layer.cornerRadius = 10
        numLabel.layer.masksToBounds = true
        numLabel.textAlignment = .center
        numLabel.font = UIFont.systemFont(ofSize: 15)
        numLabel.textColor = UIColor.white
        numLabel.isHidden = true
        self.addSubview(numLabel)

        // 按钮标题标签初始化
        titleLabel = UILabel(frame:CGRect(x: 20 , y: 0 ,
                                          width: defaultFrame.width - 20,
                                          height: 20))
        titleLabel.text = "完成"
        titleLabel.textAlignment = .center
        titleLabel.font = UIFont.systemFont(ofSize: 15)
        titleLabel.textColor = titleColor
        self.addSubview(titleLabel)
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    // 添加事件响应
    func addTarget(target: Any?, action: Selector?) {
        // 单击监听
        tapSingle = UITapGestureRecognizer(target:target,action:action)
        tapSingle!.numberOfTapsRequired = 1
        tapSingle!.numberOfTouchesRequired = 1
        self.addGestureRecognizer(tapSingle!)
    }

    // 用户数字改变时播放的动画
    func playAnimate() {
        // 从小变大,且有弹性效果
        self.numLabel.transform = CGAffineTransform(scaleX: 0.1, y: 0.1)
        UIView.animate(withDuration: 0.5, delay: 0, usingSpringWithDamping: 0.5,
                       initialSpringVelocity: 0.5, options: UIViewAnimationOptions(),
                       animations: {
                        self.numLabel.transform = CGAffineTransform.identity
        }, completion: nil)
    }
}

AlbumImagePickerViewController:

import UIKit
import Photos

// 相簿列表项
struct AlbumItem {
    // 相簿名称
    var title:String?
    // 相簿内的资源
    var fetchResult:PHFetchResult<PHAsset>
}
// 相簿列表页控制器
class AlbumImagePickerViewController: UIViewController {

    // 显示相簿列表项的表格
    @IBOutlet weak var tableView: UITableView!

    // 相簿列表项集合
    var items: [AlbumItem] = []

    // 每次最多可选择的照片数量
    var maxSelected: Int = Int.max

    // 照片选择完毕后的回调
    var completeHandler: ((_ assets:[PHAsset])->())?

    // 从xib或者storyboard加载完毕就会调用
    override func awakeFromNib() {
        super.awakeFromNib()

        // 申请权限
        PHPhotoLibrary.requestAuthorization({ (status) in
            if status != .authorized {
                return
            }

            // 列出所有系统的智能相册
            let smartOptions = PHFetchOptions()
            let smartAlbums = PHAssetCollection.fetchAssetCollections(with: .smartAlbum, subtype: .albumRegular, options: smartOptions)
            self.convertCollection(collection: smartAlbums)

            // 列出所有用户创建的相册
            let userCollections = PHCollectionList.fetchTopLevelUserCollections(with: nil)
            self.convertCollection(collection: userCollections as! PHFetchResult<PHAssetCollection>)

            // 相册按包含的照片数量排序(降序)
            self.items.sort { (item1, item2) -> Bool in
                return item1.fetchResult.count > item2.fetchResult.count
            }

            // 异步加载表格数据,需要在主线程中调用reloadData() 方法
            DispatchQueue.main.async{
                self.tableView?.reloadData()

                // 首次进来后直接进入第一个相册图片展示页面(相机胶卷)
                if let imageCollectionVC = self.storyboard?
                    .instantiateViewController(withIdentifier: "ImageCollectionVC")
                    as? AlbumImageCollectionViewController{
                    imageCollectionVC.title = self.items.first?.title
                    imageCollectionVC.assetsFetchResults = self.items.first?.fetchResult
                    imageCollectionVC.completeHandler = self.completeHandler
                    imageCollectionVC.maxSelected = self.maxSelected
                    self.navigationController?.pushViewController(imageCollectionVC, animated: false)
                }
            }
        })
    }

    // 页面加载完毕
    override func viewDidLoad() {
        super.viewDidLoad()

        // 设置标题
        title = "相簿"
        // 设置表格相关样式属性
        self.tableView.separatorInset = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
        self.tableView.rowHeight = 55
        // 添加导航栏右侧的取消按钮
        let rightBarItem = UIBarButtonItem(title: "取消", style: .plain, target: self, action:#selector(cancelBtnClicked) )
        self.navigationItem.rightBarButtonItem = rightBarItem
        self.tableView.delegate = self
        self.tableView.dataSource = self
    }

    // 转化处理获取到的相簿
    private func convertCollection(collection:PHFetchResult<PHAssetCollection>){
        for i in 0..<collection.count{
            // 获取出但前相簿内的图片
            let resultsOptions = PHFetchOptions()
            resultsOptions.sortDescriptors = [NSSortDescriptor(key: "creationDate", ascending: false)]
            resultsOptions.predicate = NSPredicate(format: "mediaType = %d", PHAssetMediaType.image.rawValue)
            let c = collection[i]
            let assetsFetchResult = PHAsset.fetchAssets(in: c , options: resultsOptions)

            // 没有图片的空相簿不显示
            if assetsFetchResult.count > 0 {
                let title = titleOfAlbumForChinese(title: c.localizedTitle)
                items.append(AlbumItem(title: title, fetchResult: assetsFetchResult))
            }
        }
    }

    // 由于系统返回的相册集名称为英文,我们需要转换为中文
    private func titleOfAlbumForChinese(title:String?) -> String? {
        if title == "Slo-mo" {
            return "慢动作"
        } else if title == "Recently Added" {
            return "最近添加"
        } else if title == "Favorites" {
            return "个人收藏"
        } else if title == "Recently Deleted" {
            return "最近删除"
        } else if title == "Videos" {
            return "视频"
        } else if title == "All Photos" {
            return "所有照片"
        } else if title == "Selfies" {
            return "自拍"
        } else if title == "Screenshots" {
            return "屏幕快照"
        } else if title == "Camera Roll" {
            return "相机胶卷"
        }
        return title
    }

    // 取消按钮点击监听方法
    func cancelBtnClicked() {
        // 退出当前vc
        self.dismiss(animated: true, completion: nil)
    }

    // 页面跳转
    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        // 如果是跳转到展示相簿缩略图页面
        if segue.identifier == "showImages"{
            // 获取照片展示控制器
            guard let imageCollectionVC = segue.destination
                as? AlbumImageCollectionViewController,
                let cell = sender as? AlbumImagePickerTableViewCell else{
                    return
            }
            // 设置回调函数
            imageCollectionVC.completeHandler = completeHandler

            // 设置标题
            imageCollectionVC.title = cell.titleLabel.text

            // 设置最多可选图片数量
            imageCollectionVC.maxSelected = self.maxSelected
            guard  let indexPath = self.tableView.indexPath(for: cell) else { return }

            // 获取选中的相簿信息
            let fetchResult = self.items[indexPath.row].fetchResult

            // 传递相簿内的图片资源
            imageCollectionVC.assetsFetchResults = fetchResult
        }
    }


    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
    }

}

// 相簿列表页控制器UITableViewDelegate,UITableViewDataSource协议方法的实现
extension AlbumImagePickerViewController: UITableViewDelegate, UITableViewDataSource {
    // 设置单元格内容
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath)
        -> UITableViewCell {
            // 同一形式的单元格重复使用,在声明时已注册
            let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
                as! AlbumImagePickerTableViewCell
            let item = self.items[indexPath.row]
            cell.titleLabel.text = "\(item.title ?? "") "
            cell.countLabel.text = "(\(item.fetchResult.count))"
            return cell
    }

    // 表格单元格数量
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return self.items.count
    }

    // 表格单元格选中
    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        tableView.deselectRow(at: indexPath, animated: true)
    }
}

extension UIViewController {
    // AlbumImagePicker提供给外部调用的接口,同于显示图片选择页面
    func presentAlbumImagePicker(maxSelected:Int = Int.max, completeHandler:((_ assets:[PHAsset])->())?) -> AlbumImagePickerViewController? {
        if let vc = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "imagePickerVC") as? AlbumImagePickerViewController {
            //设置选择完毕后的回调
            vc.completeHandler = completeHandler

            //设置图片最多选择的数量
            vc.maxSelected = maxSelected

            //将图片选择视图控制器外添加个导航控制器,并显示
            let nav = UINavigationController(rootViewController: vc)
            self.present(nav, animated: true, completion: nil)
            return vc
        }
        return nil
    }
}

AlbumImageCollectionViewController:

import UIKit
import Photos

// 图片缩略图集合页控制器
class AlbumImageCollectionViewController: UIViewController {
    // 用于显示所有图片缩略图的collectionView
    @IBOutlet weak var collectionView: UICollectionView!

    // 下方工具栏
    @IBOutlet weak var toolBar: UIToolbar!

    // 取得的资源结果,用了存放的PHAsset
    var assetsFetchResults: PHFetchResult<PHAsset>!

    // 带缓存的图片管理对象
    var imageManager: PHCachingImageManager!

    // 缩略图大小
    var assetGridThumbnailSize: CGSize!

    // 每次最多可选择的照片数量
    var maxSelected: Int = Int.max

    // 照片选择完毕后的回调
    var completeHandler: ((_ assets: [PHAsset])->())?

    // 完成按钮
    var completeButton: AlbumImageCompleteButton!

    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        // 根据单元格的尺寸计算我们需要的缩略图大小
        let scale = UIScreen.main.scale
        let cellSize = (self.collectionView.collectionViewLayout as!
            UICollectionViewFlowLayout).itemSize
        assetGridThumbnailSize = CGSize(width: cellSize.width * scale, height: cellSize.height * scale)
    }

    override func viewDidLoad() {
        super.viewDidLoad()
        self.collectionView.dataSource = self
        self.collectionView.delegate = self
        // 背景色设置为白色(默认是黑色)
        self.collectionView.backgroundColor = UIColor.white

        // 初始化和重置缓存
        self.imageManager = PHCachingImageManager()
        self.resetCachedAssets()

        // 设置单元格尺寸
        let layout = (self.collectionView.collectionViewLayout as!
            UICollectionViewFlowLayout)
        layout.itemSize = CGSize(width: UIScreen.main.bounds.size.width/4-1,
                                 height: UIScreen.main.bounds.size.width/4-1)
        // 允许多选
        self.collectionView.allowsMultipleSelection = true

        // 添加导航栏右侧的取消按钮
        let rightBarItem = UIBarButtonItem(title: "取消", style: .plain,
                                           target: self, action: #selector(cancel))
        self.navigationItem.rightBarButtonItem = rightBarItem

        // 添加下方工具栏的完成按钮
        completeButton = AlbumImageCompleteButton()
        completeButton.addTarget(target: self, action: #selector(finishSelect))
        completeButton.center = CGPoint(x: UIScreen.main.bounds.width - 50, y: 22)
        completeButton.isEnabled = false
        toolBar.addSubview(completeButton)
    }

    // 重置缓存
    func resetCachedAssets() {
        self.imageManager.stopCachingImagesForAllAssets()
    }

    // 取消按钮点击
    func cancel() {
        // 退出当前视图控制器
        self.navigationController?.dismiss(animated: true, completion: nil)
    }

    // 获取已选择个数
    func selectedCount() -> Int {
        return self.collectionView.indexPathsForSelectedItems?.count ?? 0
    }

    // 完成按钮点击
    func finishSelect(){
        // 取出已选择的图片资源
        var assets:[PHAsset] = []
        if let indexPaths = self.collectionView.indexPathsForSelectedItems{
            for indexPath in indexPaths{
                assets.append(assetsFetchResults[indexPath.row] )
            }
        }
        // 调用回调函数
        self.navigationController?.dismiss(animated: true, completion: {
            self.completeHandler?(assets)
        })
    }



    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
    }

}
// 图片缩略图集合页控制器UICollectionViewDataSource,UICollectionViewDelegate协议方法的实现
extension AlbumImageCollectionViewController: UICollectionViewDelegate, UICollectionViewDataSource {
    // CollectionView项目
    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return self.assetsFetchResults.count
    }

    // 获取单元格
    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        // 获取storyboard里设计的单元格,不需要再动态添加界面元素
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! AlbumImageCollectionViewCell
        let asset = self.assetsFetchResults[indexPath.row]
        // 获取缩略图
        self.imageManager.requestImage(for: asset, targetSize: assetGridThumbnailSize, contentMode: .aspectFill, options: nil) {
            (image, _) in
            cell.imageView.image = image
        }
        return cell
    }

    // 单元格选中响应
    func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
        if let cell = collectionView.cellForItem(at: indexPath) as? AlbumImageCollectionViewCell {
            // 获取选中的数量
            let count = self.selectedCount()
            // 如果选择的个数大于最大选择数
            if count > self.maxSelected {
                // 设置为不选中状态
                collectionView.deselectItem(at: indexPath, animated: false)
                // 弹出提示
                let title = "你最多只能选择\(self.maxSelected)张照片"
                let alertController = UIAlertController(title: title, message: nil, preferredStyle: .alert)
                let cancelAction = UIAlertAction(title:"我知道了", style: .cancel, handler:nil)
                alertController.addAction(cancelAction)
                self.present(alertController, animated: true, completion: nil)
            }
            // 如果不超过最大选择数
            else{
                // 改变完成按钮数字,并播放动画
                completeButton.num = count
                if count > 0 && !self.completeButton.isEnabled{
                    completeButton.isEnabled = true
                }
                cell.playAnimate()
            }
        }
    }

    // 单元格取消选中响应
    func collectionView(_ collectionView: UICollectionView, didDeselectItemAt indexPath: IndexPath) {
        if let cell = collectionView.cellForItem(at: indexPath) as? AlbumImageCollectionViewCell {
            // 获取选中的数量
            let count = self.selectedCount()
            completeButton.num = count
            // 改变完成按钮数字,并播放动画
            if count == 0{
                completeButton.isEnabled = false
            }
            cell.playAnimate()
        }
    }
}

至此,可以在ViewController里使用这个选择图片的控件了:

import UIKit
import Photos

class ViewController: UIViewController, UIImagePickerControllerDelegate,UINavigationControllerDelegate {

    // 存放图片的数组
    var imageArray = [UIImage]()

    // 存放图片等collectionview
    var collectionView: UICollectionView!

    // 最大图片张数
    let maxImageCount = 9

    // 添加图片按钮
    var addButton: UIButton!

    // 选择上传图片方式弹窗
    var addImageAlertViewController: UIAlertController!

    // 缩略图大小
    var imageSize: CGSize!

    override func viewDidLoad() {

        super.viewDidLoad()

        // 设置背景色
        self.view.backgroundColor = UIColor.groupTableViewBackground

        // 设置添加图片按钮相关属性
        addButton = UIButton(type: UIButtonType.custom)
        addButton.setTitle("添加图片", for: UIControlState.normal)
        addButton.addTarget(self, action: #selector(addItem(_:)), for: UIControlEvents.touchUpInside)
        addButton.backgroundColor = UIColor.init(red: 164 / 255, green: 193 / 255, blue: 244 / 255, alpha: 1)
        addButton.frame = CGRect(x: 20, y: 35, width: 100, height: 25)
        addButton.layer.masksToBounds = true
        addButton.layer.cornerRadius = 8.0

        // 设置collection的layout
        let layout = UICollectionViewFlowLayout()
        layout.itemSize = CGSize(width: 50, height: 50)
        // 列间距
        layout.minimumInteritemSpacing = 10
        // 行间距
        layout.minimumLineSpacing = 10
        // 偏移量
        layout.sectionInset = UIEdgeInsetsMake(10, 10, 10, 10)

        // 设置collectionview的大小、背景色、代理、数据源
        collectionView = UICollectionView(frame: CGRect(x: 10, y: 60, width: 200, height: self.view.frame.size.height), collectionViewLayout: layout)
        collectionView.backgroundColor = UIColor.groupTableViewBackground
        collectionView.delegate = self
        collectionView.dataSource = self

        // 注册cell
        collectionView.register(PhotoCollectionViewCell.self, forCellWithReuseIdentifier: "photoCell")

        // 选择上传照片方式的弹窗设置
        addImageAlertViewController = UIAlertController(title: "请选择上传方式", message: "相册或者相机", preferredStyle: UIAlertControllerStyle.actionSheet)
        let cancelAction = UIAlertAction(title: "取消", style: UIAlertActionStyle.cancel, handler: nil)
        let cameraAction = UIAlertAction(title: "拍照", style: UIAlertActionStyle.default, handler: {
            (action: UIAlertAction) in self.cameraAction()
        })
        let albumAction = UIAlertAction(title: "从相册选择", style: UIAlertActionStyle.default, handler: {
            (action: UIAlertAction) in self.albumAction()
        })
        self.addImageAlertViewController.addAction(cancelAction)
        self.addImageAlertViewController.addAction(cameraAction)
        self.addImageAlertViewController.addAction(albumAction)

        self.view.addSubview(addButton)
        self.view.addSubview(collectionView)
    }

    override func viewWillAppear(_ animated: Bool) {
        // 获取缩略图的大小
        let cellSize = (self.collectionView.collectionViewLayout as! UICollectionViewFlowLayout).itemSize
        self.imageSize = cellSize
    }

    // MARK: - 删除图片按钮监听方法
    func removeItem(_ button: UIButton) {
        // 数据变更
        self.collectionView.performBatchUpdates({
            self.imageArray.remove(at: button.tag)
            let indexPath = IndexPath(item: button.tag, section: 0)
            let arr = [indexPath]
            self.collectionView.deleteItems(at: arr)
        }, completion: {(completion) in
            self.collectionView.reloadData()
        })

        // 判断是否使添加图片按钮生效
        if imageArray.count < 9 {
            self.addButton.isEnabled = true
            self.addButton.backgroundColor = UIColor.init(red: 164 / 255, green: 193 / 255, blue: 244 / 255, alpha: 1)
        }
    }

    // MARK: - 添加图片按钮监听方法
    func addItem(_ button: UIButton) {
        self.present(addImageAlertViewController, animated: true, completion: nil)
    }

    // MARK: - 拍照监听方法
    func cameraAction() {
        if UIImagePickerController.isSourceTypeAvailable(UIImagePickerControllerSourceType.camera) {
            // 创建图片控制器
            let picker = UIImagePickerController()

            // 设置代理
            picker.delegate = self

            // 设置来源
            picker.sourceType = UIImagePickerControllerSourceType.camera

            // 允许编辑
            picker.allowsEditing = true

            // 打开相机
            self.present(picker, animated: true, completion: { 
                () -> Void in
            })
        }else {
            // 弹出提示
            let title = "找不到相机"
            let alertController = UIAlertController(title: title, message: nil, preferredStyle: .alert)
            let cancelAction = UIAlertAction(title:"我知道了", style: .cancel, handler:nil)
            alertController.addAction(cancelAction)
            self.present(alertController, animated: true, completion: nil)
        }
    }

    // MARK: - 相册监听方法
    func albumAction() {
        // 可选照片数量
        let count = maxImageCount - imageArray.count

        // 开始选择照片,最多允许选择count张
        _ = self.presentAlbumImagePicker(maxSelected: count) { (assets) in

            // 结果处理
            for asset in assets {
                // 从asset获取image
                let image = self.PHAssetToUIImage(asset: asset)

                // 数据变更
                self.collectionView.performBatchUpdates({
                    let indexPath = IndexPath(item: self.imageArray.count, section: 0)
                    let arr = [indexPath]
                    self.collectionView.insertItems(at: arr)
                    self.imageArray.append(image)
                }, completion: {(completion) in
                    self.collectionView.reloadData()
                })

                // 判断是否使添加图片按钮失效
                if self.imageArray.count > 8 {
                    self.addButton.isEnabled = false
                    self.addButton.backgroundColor = UIColor.darkGray
                }
            }
        }
    }

    // MARK: - 将PHAsset对象转为UIImage对象
    func PHAssetToUIImage(asset: PHAsset) -> UIImage {
        var image = UIImage()

        // 新建一个默认类型的图像管理器imageManager
        let imageManager = PHImageManager.default()

        // 新建一个PHImageRequestOptions对象
        let imageRequestOption = PHImageRequestOptions()

        // PHImageRequestOptions是否有效
        imageRequestOption.isSynchronous = true

        // 缩略图的压缩模式设置为无
        imageRequestOption.resizeMode = .none

        // 缩略图的质量为高质量,不管加载时间花多少
        imageRequestOption.deliveryMode = .highQualityFormat

        // 按照PHImageRequestOptions指定的规则取出图片
        imageManager.requestImage(for: asset, targetSize: self.imageSize, contentMode: .aspectFill, options: imageRequestOption, resultHandler: {
            (result, _) -> Void in
            image = result!
        })
        return image
    }

    // MARK: - 相机图片选择器
    func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
        // 将相机刚拍好的照片拿出来
        let gotImage = info[UIImagePickerControllerOriginalImage] as! UIImage

        // 数据变更
        self.collectionView.performBatchUpdates({
            let indexPath = IndexPath(item: self.imageArray.count, section: 0)
            let arr = [indexPath]
            self.collectionView.insertItems(at: arr)
            self.imageArray.append(gotImage)
            print(self.imageArray.count)

        }, completion: {(completion) in
            self.collectionView.reloadData()
        })

        // 判断是否使添加图片按钮失效
        if imageArray.count > 8 {
            self.addButton.isEnabled = false
            self.addButton.backgroundColor = UIColor.darkGray
        }

        // 关闭此页面
        self.dismiss(animated: true, completion: nil)
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }

}

// MARK: - collection代理方法实现
extension ViewController: UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {
    // 每个区的item个数
    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return imageArray.count
    }

    // 分区个数
    func numberOfSections(in collectionView: UICollectionView) -> Int {
        return 1
    }

    // 自定义cell
    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "photoCell", for: indexPath) as! PhotoCollectionViewCell
        cell.imageView.image = imageArray[indexPath.item]
        cell.button.addTarget(self, action: #selector(removeItem(_:)), for: UIControlEvents.touchUpInside)
        cell.button.tag = indexPath.row
        return cell
    }

    // 是否可以移动
    func collectionView(_ collectionView: UICollectionView, canMoveItemAt indexPath: IndexPath) -> Bool {
        return true
    }
}

参考:
相册图片多选功能的实现
Swift中将PHAsset对象转为UIImage对象
整个项目源码地址