Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Alamofire download issue

Tags:

I am trying to download this picture in my code using Alamofire 4.0.0 with Xcode 8.0 and Swift 3.0.

Here is my request:

    func download(_ path: String, _ completionHandler: @escaping (Any?) -> ()) {
        let stringURL = "https://slove.tulleb.com/uploads/6/6/0/2/66027561/2791411.jpg-1447979839.png"

        print("Requesting \(stringURL)...")

        _ = Alamofire.download(stringURL)
            .responseData { response in
                print(response)

                if let data = response.result.value {
                    completionHandler(UIImage(data: data))
                } else {
                    completionHandler(nil)
                }
        }
    }

I get the following answer from the server:

FAILURE: responseSerializationFailed(Alamofire.AFError.ResponseSerializationFailureReason.inputFileReadFailed(file:///private/var/mobile/Containers/Data/Application/50400F41-47FD-4276-8903-F48D942D064A/tmp/CFNetworkDownload_D1Aqkh.tmp))

I don't have any idea on how to fix this... Is Alamofire new version having some issues or is it me forgetting something somewhere?

Thanks!

like image 468
Tulleb Avatar asked Sep 14 '16 12:09

Tulleb


People also ask

What is the latest version of Alamofire?

Alamofire v5. 6.2 Release Notes 🚀 Released on 2022-07-17.

Is Alamofire an asynchronous?

Networking in Alamofire is done asynchronously. Asynchronous programming may be a source of frustration to programmers unfamiliar with the concept, but there are very good reasons for doing it this way.

Is Alamofire a framework?

And that's it! The Alamofire. framework is automagically added as a target dependency, linked framework and embedded framework in a copy files build phase which is all you need to build on the simulator and a device.

Is Alamofire open source?

The Alamofire Software Foundation is a 501(c)(3) non-profit with the purpose of promoting, supporting, and advancing its open-source software projects.


Video Answer


1 Answers

Official answer from cnoon (Alamofire member):

Hi @Tulleb,

Apologies for not getting back to you sooner. The example @katopz is not the same type of request. That example demonstrates how to use a data task, not a download task. If you don't wish to download the file, you can instead do the following:

Alamofire.request(url).responseData { response in
     guard let data = response.result.value else { return }
     let image = UIImage(data: data)
     print(image)
}

However, to answer you're original question, you're running into a sandbox permissions issue. We allow you to use the download APIs without specifying a destination closure for operating systems like macOS where you can access files outside of your own sandbox. However, on iOS, you cannot directly access the data of a file that is outside of your sandbox. That's why you are seeing the .inputFileReadFailed error.

There are a couple ways you can solve this issue.

Option 1

You can download the data using the request API as shown above which downloads the image data into memory, not to disk.

Option 2

You can move the file into your sandbox before accessing the data using a destination closure. Here's an example of how to do that:

let destination: DownloadRequest.DownloadFileDestination = { _, _ in
let documentsPath = NSSearchPathForDirectoriesInDomains(.documentDirectory,
.userDomainMask, true)[0]
let documentsURL = URL(fileURLWithPath: documentsPath, isDirectory: true)
let fileURL = documentsURL.appendingPathComponent("image.png")

return (fileURL, [.removePreviousFile, .createIntermediateDirectories]) }

Alamofire.download("https://httpbin.org/image/png", to:
destination).responseData { response in
    debugPrint(response)

    if let data = response.result.value {
        let image = UIImage(data: data)
        print(image)
    } else {
        print("Data was invalid")
    }
}

// Outputs:

// [Request]: https://httpbin.org/image/png // [Response]: { URL: https://httpbin.org/image/png } { status code: 200, headers { // "Access-Control-Allow-Origin" = "*"; // "Content-Length" = 8090; // "Content-Type" = "image/png"; // Date = "Sat, 24 Sep 2016 21:34:25 GMT"; //
Server = nginx; // "access-control-allow-credentials" = true; // } } // [TemporaryURL]: /private/var/mobile/Containers/Data/Application/25612024-9A05-4ED5-AF3B-A98E22DEAD7A/tmp/CFNetworkDownload_fD9sXf.tmp // [DestinationURL]: /var/mobile/Containers/Data/Application/25612024-9A05-4ED5-AF3B-A98E22DEAD7A/Documents/image.png // [ResumeData]: 0 bytes // [Result]: SUCCESS: 8090 bytes // [Timeline]: Timeline: { "Request Start Time": 496445664.792, "Initial Response Time": 496445665.651, "Request Completed Time": 496445665.655, "Serialization Completed Time": 496445665.655, "Latency": 0.860 secs, "Request Duration": 0.863 secs, "Serialization Duration": 0.000 secs, "Total Duration": 0.864 secs } // Optional(, {100, 100}) You MUST use a destination closure if you need to download the file to disk. The temporary file can only be accessed inside the delegate callback which is handled internally in Alamofire. If you do not specify a destination closure on iOS, the temporaryURL will always point to where the temp file was previously stored, but has been cleaned up.

Summary

So in summary, if you don't need to download the data to disk, then you want Option 1. If you do want to save the file on disk, then you want Option 2.

Cheers. 🍻

like image 141
Tulleb Avatar answered Sep 21 '22 06:09

Tulleb