ピンチアウトでズーム可能なUIImageViewを作成する。

# ストーリーボードの準備
ViewControllerのsubViewにScrollViewを配置します。
ImageViewはコードで追加します。
<img width="741" alt="スクリーンショット 2019-10-08 19.01.27.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/418332/f5a44840-2bde-8de4-4179-93577a7ee621.png">

# ソースコード
``` swift:ModalImageViewController.swift
import UIKit

class ModalImageViewController: UIViewController, UIScrollViewDelegate {
    
    @IBOutlet weak var scrollView: UIScrollView!
    var image: UIImage? = nil
    var imageUrl: String = ""
    var imageView = UIImageView()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        // デリゲートを設定
        self.scrollView.delegate = self
        // 最大倍率・最小倍率を設定する
        self.scrollView.maximumZoomScale = 5.0
        self.scrollView.minimumZoomScale = 1.0
        
        // imageViewをscrollViewいっぱいに生成
        self.imageView.frame = CGRect(x:0,y:0,width:view.frame.width,height:view.frame.height)
        scrollView.addSubview(imageView)
        self.imageView.contentMode = .scaleAspectFit
        
        guard let _noImage = UIImage(named:"noimage") else { return }
        self.loadImage(self.imageUrl, _noImage)
        
    }
    
    func viewForZooming(in scrollView: UIScrollView) -> UIView? {
        return self.imageView
    }

    func scrollViewDidZoom(_ scrollView: UIScrollView) {
        // ズーム終了時の処理
    }

    func scrollViewWillBeginZooming(_ scrollView: UIScrollView, with view: UIView?) {
        // ズーム開始時の処理
    }

    func zoomForScale(scale:CGFloat, center: CGPoint) -> CGRect{
        var zoomRect: CGRect = CGRect()
        zoomRect.size.height = self.scrollView.frame.size.height / scale
        zoomRect.size.width = self.scrollView.frame.size.width  / scale
        zoomRect.origin.x = center.x - zoomRect.size.width / 2.0
        zoomRect.origin.y = center.y - zoomRect.size.height / 2.0
        return zoomRect
    }
    
    
    /// 画像を非同期で取得して、ImageViewに設定します。
    /// - Parameter urlString: url文字列
    /// - Parameter defaultImage: 取得失敗したときの画像を入れてください
    private func loadImage(_ urlString: String, _ defaultImage: UIImage) -> Void {

        guard let _url = URL(string: urlString)
            else {
                self.imageView.isHidden = true
                return
        }

        DispatchQueue.global().async {
            do {
                let imageData: Data? = try Data(contentsOf: _url)
                DispatchQueue.main.async {
                    
                    if
                        let data = imageData,
                        let image = UIImage(data: data) {
                        
                        self.imageView.image =  image
                        
                    } else {
                        self.imageView.image =  defaultImage
                    }
                    
                }
            }
            catch {
                DispatchQueue.main.async {
                    self.imageView.image =  defaultImage
                }
            }
        }
    }
}

``````

# 実行結果
シミュレーターで動かす場合は、「option」＋ドラッグでできます。
![タイトルなし.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/418332/62faeb31-f4df-8767-6568-be3b131fcd4a.gif)