Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Create Zip file from an array of data (coreData Images) and share via the .zip file via Email

I have an (n) of data (UIImage JPEG) inside my CoreData.

let imageData: [Data]... 

I have already this two frameworks/ Pods: Zip and ZIPFoundation

I have a few Question about that:

  1. I need to create a temp URL for each of my imageData?
  2. If yes, I have to add tempURL.appendingPathExtension("jpg") to each temp URLs before or after call data.write(to: tempURL) ?

After that, I have an Array of URLs, so I just need to create a Zip File and share it. But it doesn't work, I get a .zip - .cpgz Loop on my Mac.

 private func createURLsFrom(imageData: [ImageData]?) {
    var urlArray = [URL]()
    imageData?.forEach { imData in
        if let data = imData.imageData,
        let tempURL = NSURL.fileURL(withPathComponents: [NSTemporaryDirectory(), NSUUID().uuidString])?.appendingPathExtension("jpg") {

            do {
                try data.write(to: tempURL)
                urlArray.append(tempURL)

            } catch {...}
        }
    }
    self.createZipFile(urlArray: urlArray)
}



private func createZipFile(urlArray: [URL]) {
    if let zipURL = try? Zip.quickZipFiles(urlArray, fileName: "ZIP_Test1") {
        self.sendEmailWith(dataURL: zipURL)
    } else {...}
}


private func sendEmailWith(dataURL: URL) {
    if MFMailComposeViewController.canSendMail() {

        let mailComposer = MFMailComposeViewController()
        mailComposer.mailComposeDelegate = self

        mailComposer.setSubject("setSubject")
        mailComposer.setMessageBody("setMessageBody", isHTML: false)
        mailComposer.addAttachmentData(dataURL.dataRepresentation, mimeType: "application/zip", fileName: ("ZIP_Test1.zip"))

        self.present(mailComposer, animated: true, completion: nil)
    }
}

What am I doing wrong :(

like image 340
A. Amini Avatar asked Jul 16 '19 21:07

A. Amini


1 Answers

It's a bit lengthy, and––disclaimer––untested. Let me know if it works or if you have any questions.

Create a temp directory for all the files:

func createTempDirectory() -> URL? {
    if let documentDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first {
        let dir = documentDirectory.appendingPathComponent("temp-dir-\(UUID().uuidString)")
        do {
            try FileManager.default.createDirectory(atPath: dir.path, withIntermediateDirectories: true, attributes: nil)
        } catch {
            print(error.localizedDescription)
        }
        return dir
    } else {
        return nil
    }
}

Save all the images to the temp directory:

func saveImages(data: [Data]) -> URL? {
    guard let directory = createTempDirectory() else { return nil }

    do {
        for (i, imageData) in data.enumerated() {
            try imageData.write(to: directory.appendingPathComponent("image\(i).jpg"))
        }
        return directory
    } catch {
        return nil
    }
}

Get the URL for the zipped file. This is an optional in case an error occurred along the way. Also, done on a background thread because it could take a bit of time, and you don't want to block the main thread.

func zipImages(data: [Data], completion: @escaping ((URL?) -> ())) {
    DispatchQueue.main.async {
        guard let directory = saveImages(data: data) else {
            completion(nil)
            return
        }

        do {
            let zipFilePath = try Zip.quickZipFiles([directory], fileName: "archive-\(UUID().uuidString)")
            completion(zipFilePath)
        } catch {
            completion(nil)
        }
    }
}

After you send the file, you'll probably want to delete the temp directory so your app size doesn't start growing.

like image 81
Daniel Avatar answered Oct 16 '22 15:10

Daniel