iOS12 betaでダウンロード再開処理の検証

Xcode 10 beta 6のiOS12シミュレータで検証しました。

#ダウンロードを再開するためのplistの内容
下記のコードはAlamofireでファイルをダウンロードするリクエストです。
request.cancel()を呼ぶとエラーを返します。そのエラーの中にダウンロードを再開するためのplistが含まれています。

```swift
let request = self.manager
        .download(String(format : DownloadService.requestFormat, url, id), to: destination)
        .downloadProgress(closure: {[weak self] progress  in
            guard let wself = self else {
                return
            }
                
            if let progressClosure = wself.progressClosure {
                progressClosure(id, progress.fractionCompleted)
            }
        })
        .response(completionHandler: {[weak self] response in
            guard let wself = self else {
                return
            }
                
            guard let error = response.error else {
                if let completedClosure = wself.completedClosure {
                    let cacheURL = FileManager.default.urls(for: .cachesDirectory, in: .userDomainMask)[0]
                    let fileUrl = cacheURL.appendingPathComponent(String(format : DownloadService.resumeFileFormat, id))
                    if FileManager.default.fileExists(atPath: fileUrl.path) {
                        do {
                            try FileManager.default.removeItem(at: fileUrl)
                        } catch {
                            print("file delete error")
                        }
                    }
                        
                    completedClosure(id)
                }
                return
            }
                
            //キャンセルの場合もエラーが返ってくる
            guard let resumeData = response.resumeData else {
                if let errorClosure = wself.errorClosure {
                    errorClosure(error)
                }
                return
            }
             
            do {
                //plistを保存する
                let cacheURL = FileManager.default.urls(for: .cachesDirectory, in: .userDomainMask)[0]
                let fileUrl = cacheURL.appendingPathComponent(String(format : DownloadService.resumeFileFormat, id))
                try resumeData.write(to: fileUrl)
                    
                if let pauseClosure = wself.pauseClosure {
                    pauseClosure(id)
                }
            } catch {
                print("plist write error")
                return
            }
                
            return
        })
```

今回調査したところ、下図のようにiOS11とiOS12でplistの内容が変更されていました。
![スクリーンショット 2018-08-19 18.41.47.png](https://qiita-image-store.s3.amazonaws.com/0/33300/54cf9006-0b19-b0e3-845d-768c423ce6b9.png)

以前まではplistを保存する方法としてPropertyListSerialization [propertyList(from:options:format:)](https://developer.apple.com/documentation/foundation/propertylistserialization/1409678-propertylist)でNSDictionaryに変換してから[write(to:atomically:)](https://developer.apple.com/documentation/foundation/nsdictionary/1409634-write)で保存していました。

```swift
//plistを保存する
let plist = try PropertyListSerialization.propertyList(from: resumeData, options: [.mutableContainersAndLeaves], format: nil)
let cacheURL = FileManager.default.urls(for: .cachesDirectory, in: .userDomainMask)[0]
let fileUrl = cacheURL.appendingPathComponent(String(format : DownloadService.resumeFileFormat, id))
if !(plist as! NSDictionary).write(to: fileUrl, atomically: true) {
    print("plist write error")
    return
}
```
iOS12では保存できなくなっていたので、Data [write(to:options:)](https://developer.apple.com/documentation/foundation/data/1779858-write)で保存するように変更しました。

#バグ
ダウンロード中にアプリを閉じて、再起動すると未完了のURLSessionTaskがSessionManager.sessionの中に残っています。キャンセルしたときと同様にURLSessionTask.errorの中にplistがあります。このplistを使うことでアプリを再起動してもダウンロードを継続することができます。
このplistでダウンロードを再開してから、もう1回アプリの再起動を行うとURLSessionTaskのoriginalRequestが消失します...。

#iOS12の検証に使ったプロジェクト
[github](https://github.com/h-shiraishi/BackgroundDownload)