+4

Xử lý files trong Swift

1. Chọn files trong device

1.1 Chọn file

Để chọn được files trong iOS bạn có thể dùng UIDocumentPickerViewController

Ví dụ:

import UIKit
import MobileCoreServices // Bạn cần import MobileCoreServices vì kiểu dữ liệu của files (PDF, PNG, ....) được định nghĩa ở đây

class ViewController: UIViewController {

    func showFilePicker() {
        // kUTTypePDF là lọc files PDF, bạn có thể thêm nhiều kiểu dữ liệu khác nếu cần.
        let documentPicker = UIDocumentPickerViewController(documentTypes: [kUTTypePDF as NSString as String],
                                                            in: .import)
        documentPicker.delegate = self
        documentPicker.modalPresentationStyle = .formSheet
        if #available(iOS 11.0, *) {
            documentPicker.allowsMultipleSelection = false
        }
        self.present(documentPicker, animated: true, completion: nil)
    }

}

extension ViewController: UIDocumentPickerDelegate {

    func documentPicker(_ controller: UIDocumentPickerViewController, didPickDocumentAt url: URL) {
        print(url)
    }

    func documentPicker(_ controller: UIDocumentPickerViewController, didPickDocumentsAt urls: [URL]) {
        print(urls)
    }

    func documentPickerWasCancelled(_ controller: UIDocumentPickerViewController) {
    }

}

1.2 Lấy kích thước của file

let size = sizeForLocalFilePath(filePath: url.path)

func sizeForLocalFilePath(filePath: String) -> UInt64 {
    do {
        let fileAttributes = try FileManager.default.attributesOfItem(atPath: filePath)
        if let fileSize = fileAttributes[FileAttributeKey.size]  {
            return (fileSize as! NSNumber).uint64Value
        } else {
            print("Failed to get a size attribute from path: \(filePath)")
        }
    } catch {
        print("Failed to get file attributes for local path: \(filePath) with error: \(error)")
    }
    return 0
}

2. Mở file

Để mở 1 file bạn có thể dùng UIDocumentInteractionController. Bạn cần truyền vào file đã được download về device nhé, chứ files URL trỏ đến server thì không mở được đâu 😄

class ViewController: UIViewController {

    var documentInteractionController: UIDocumentInteractionController?

    func openDocument(fileUrl: URL) {
        documentInteractionController = UIDocumentInteractionController(url: fileUrl)
        documentInteractionController?.delegate = self
        documentInteractionController?.presentPreview(animated: true)
    }

}

extension ViewController: UIDocumentInteractionControllerDelegate {

    func documentInteractionControllerViewControllerForPreview(
        _ controller: UIDocumentInteractionController) -> UIViewController {
        return self
    }

}

3. Download file

Việc download file thì có vô vàn cách + libs hỗ trợ. Nhưng trong bài này mình sẽ dùng URLSessionDownloadTask default của iOS nhé:

class ViewController: UIViewController {

    var downloadTask: URLSessionDownloadTask?
    var backgroundSession: URLSession?

}

extension ViewController {

    func downloadFile(documentUrl: URL) {
        let backgroundSessionConfiguration = URLSessionConfiguration.background(withIdentifier: "backgroundSession")
        backgroundSession = Foundation.URLSession(configuration: backgroundSessionConfiguration, delegate: self,
                                                  delegateQueue: OperationQueue.main)
        let request = URLRequest(url: documentUrl)
        downloadTask = backgroundSession?.downloadTask(with: request)
        downloadTask?.resume()
        // Show loading ở đây nhé
    }

    // Hàm này để lưu file dựa theo tên file mà server trả về
    fileprivate func getDestinationFileUrl(response: URLResponse) -> URL {
        var docsURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0]
        let filename = response.suggestedFilename ?? "file.pdf"
        docsURL.appendPathComponent(filename)
        return docsURL
    }

}

extension ViewController: URLSessionDownloadDelegate {

    func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didWriteData bytesWritten: Int64,
                    totalBytesWritten: Int64, totalBytesExpectedToWrite: Int64) {
        let progress = CGFloat(totalBytesWritten) / CGFloat(totalBytesExpectedToWrite)
        print("progress: \(progress)")
        // Hiển thị progress nếu thích :D
    }

    func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didFinishDownloadingTo location: URL) {
        // Ẩn loading
        guard let response = downloadTask.response else {
            print(downloadTask.error?.localizedDescription ?? "Loading file error.")
            return
        }
        let destinationURL = getDestinationFileUrl(response: response)

        // Đoạn này mình xoá file cũ đi nếu có (logic app mình thế ;) )
        let fileManager = FileManager.default
        if fileManager.fileExists(atPath: destinationURL.path) {
            try? fileManager.removeItem(at: destinationURL)
        }
        do {
            try fileManager.moveItem(at: location, to: destinationURL)

            // Mở file đã download được
            openDocument(fileUrl: destinationURL)
        } catch {
            print(error)
        }
    }

    func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) {
        // Ẩn loading
        print(error)
    }

}

4. Upload file

Trong ví dụ này mình sẽ dùng Alamofire để upload 1 ảnh png nhé

func requestWith(endUrl: String, imageData: Data?, parameters: [String : Any],
                 onCompletion: ((Any?) -> Void)? = nil,
                 onError: ((Error?) -> Void)? = nil){

    let url = "http://google.com" /* your API url */

    let headers: HTTPHeaders = [
        /* "Authorization": "your_access_token",  in case you need authorization header */
        "Content-type": "multipart/form-data"
    ]

    Alamofire.upload(multipartFormData: { (multipartFormData) in
        for (key, value) in parameters {
            multipartFormData.append("\(value)".data(using: String.Encoding.utf8)!, withName: key as String)
        }

        if let data = imageData{
            multipartFormData.append(data, withName: "image", fileName: "image.png", mimeType: "image/png")
        }

    }, usingThreshold: UInt64.init(), to: url, method: .post, headers: headers) { (result) in
        switch result{
        case .success(let upload, _, _):
            upload.responseJSON { response in
                print("Succesfully uploaded")
                if let err = response.error{
                    onError?(err)
                    return
                }
                onCompletion?(response.value)
            }
        case .failure(let error):
            print("Error in upload: \(error.localizedDescription)")
            onError?(error)
        }
    }
}
(Nguồn: https://medium.com/theappspace/alamofire-4-multipart-file-upload-with-swift-3-174df1ef84c1)

Kết luận: Trong bài viết mình đã giới thiệu qua những thao tác cơ bản khi làm việc với file trong iOS. Hi vọng có thể giúp được cho các bạn. (y)


All rights reserved

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí