3

In case I want to check if the file exists on my iPhone, just use the following code:

  let filePath = fileName.path
         let fileManager = FileManager.default
         if fileManager.fileExists (atPath: filePath) {

}

How can I check if there is a pdf / jpg / png file at the URL: www.myname.com/files/file1.jpg or www.myname.com/files/file2.pdf etc.?

Could I ask for an example of such a function - but for files on internet web servers?

UPDATE

func remoteFileExistsAt(url: URL, completion: @escaping (Bool) -> Void) {
    let checkSession = URLSession.shared
    var request = URLRequest(url: url)
    request.httpMethod = "HEAD"
    request.timeoutInterval = 1.0 // Adjust to your needs

    let task = checkSession.dataTask(with: request) { (data, response, error) -> Void in
        if let httpResp = response as? HTTPURLResponse {
            completion(httpResp.statusCode == 200)
        }
    }
    task.resume()
}

Is it possible to check in this function whether the file is of JPG or PNG type? If so - then we also return true, and if not, false?

triff
  • 157
  • 3
  • 12

3 Answers3

3

Updated:

After the discussion on the comments section, the code is updated to work in more correct way.

You should check for the mimeType of the URLResponse object rather than checking whether the image could be represented as UIImageJPEGRepresentation/UIImagePNGRepresentation or not. Because it doesn't guarantee that the resource is actually a jpg/jpeg or png.

So the mimeType should be the most reliable parameter that needs to considered here.

enum MimeType: String {
    case jpeg = "image/jpeg"
    case png = "image/png"
}

func remoteResource(at url: URL, isOneOf types: [MimeType], completion: @escaping ((Bool) -> Void)) {
    var request = URLRequest(url: url)
    request.httpMethod = "HEAD"
    let task = URLSession.shared.dataTask(with: request) { (data, response, error) in
        guard let response = response as? HTTPURLResponse, response.statusCode == 200, let mimeType = response.mimeType else {
            completion(false)
            return
        }
        if types.map({ $0.rawValue }).contains(mimeType) {
            completion(true)
        } else {
            completion(false)
        }
    }
    task.resume()
}

Verify with this:

let jpegImageURL = URL(string: "https://vignette.wikia.nocookie.net/wingsoffire/images/5/54/Panda.jpeg/revision/latest?cb=20170205005103")!
remoteResource(at: jpegImageURL, isOneOf: [.jpeg, .png]) { (result) in
    print(result)  // true
}

let pngImageURL = URL(string: "https://upload.wikimedia.org/wikipedia/commons/6/69/Giant_panda_drawing.png")!
remoteResource(at: pngImageURL, isOneOf: [.jpeg, .png]) { (result) in
    print(result)  //true
}

let gifImageURL = URL(string: "https://media1.tenor.com/images/f88f6514b1a800bae53a8e95b7b99172/tenor.gif?itemid=4616586")!
remoteResource(at: gifImageURL, isOneOf: [.jpeg, .png]) { (result) in
    print(result)  //false
}

Previous Answer:

You can check if the remote data can be represented as UIImageJPEGRepresentation or UIImagePNGRepresentation. If yes, you can say that remote file is either JPEG or PNG.

Try this:

func remoteResource(at url: URL, isImage: @escaping ((Bool) -> Void)) {
    let request = URLRequest(url: url)

    let task = URLSession.shared.dataTask(with: request) { (data, response, error) in
        if let data = data, let image = UIImage(data: data) {
            if let _ = UIImageJPEGRepresentation(image, 1.0) {
                isImage(true)
            } else if let _ = UIImagePNGRepresentation(image) {
                isImage(true)
            } else {
                isImage(false)
            }

        } else {
            isImage(false)
        }
    }
    task.resume()
}

Usage:

let imageURL = URL(string: "http://domaind.com/index.php?action=GET_PHOTO&name=102537.jpg&resolution=FHD&lang=PL&region=1")!
remoteResource(at: imageURL) { (isImage) in
    print(isImage) // prints true for your given link
}
nayem
  • 7,285
  • 1
  • 33
  • 51
  • 1
    This is not the ideal answer since this fully downloads the image, creates a `UIImage`, and then discards both. Why not do just a HEAD request and check the mimetype in the response? This would be much faster and waste far less of a user's data plan. – rmaddy May 23 '18 at 14:15
  • 1
    One other issue. This code doesn't actually verify whether the URL is a PNG or JPG. This only verifies that the URL references a file or data that is supported by UIImage. If the URL is a GIF, this code will report "true". `UIImageJPEGRepresentation` does not tell you that the `UIImage` was created from a JPG. You can load a PNG and `UIImageJPEGRepresentation` will in turn give you a JPG of the original image. – rmaddy May 23 '18 at 17:36
  • Oh well. Great. Couldn't think of that. But now, I'm afraid _if the `mimeType` is actually reliable to check for?_ What if the source carries/reports wrong information? – nayem May 23 '18 at 17:57
  • Yes, the server could lie about about the mimetype. That's a trade-off that needs to be considered. At a minimum you need to update the code in your answer by eliminating the use of `UIImageJPEGRepresentation` and `UIImagePNGRepresentation`. – rmaddy May 23 '18 at 18:04
  • @rmaddy I've updated the code. Can you please look at it and say if that should do the work? – nayem May 23 '18 at 18:47
  • Looks good. While beyond the scope of the original question, a helper function like this could be made more general by taking an array of desired mime types and indicating whether the URL matches one of those supplied types. Might be more useful than being hardcoded for specific types. This is more a thought for the OP or anyone seeing this in the future. Don't feel compelled to update your answer further. – rmaddy May 23 '18 at 19:16
  • @rmaddy Thanks for your thoughtful informations. I've updated accordingly – nayem May 23 '18 at 20:01
0

If you want to know the file exists on a server, then it requires sending a HTTP request and receiving the response.

Please try with following code,

func remoteFileExistsAt(url: URL, completion: @escaping (Bool) -> Void) {
    let checkSession = URLSession.shared
    var request = URLRequest(url: url)
    request.httpMethod = "HEAD"
    request.timeoutInterval = 1.0 // Adjust to your needs

    let task = checkSession.dataTask(with: request) { (data, response, error) -> Void in
        if let httpResp = response as? HTTPURLResponse {
            completion(httpResp.statusCode == 200)
        } else {
            completion(false) 
        }
    }
    task.resume()
}

UPDATE

remoteFileExistsAt(url: URL(string: "http://domaind.com/index.php?action=GET_PHOTO&name=102537.jpg&resolution=FHD&lang=PL&region=1")!) { (success) in
    print(success)
}
PPL
  • 6,357
  • 1
  • 11
  • 30
  • I have Image: https://www.udanewakacje.net/uploads/portal/atrakcje/mini_31801dfltybegjmotvwybhjwy6615457172.jpg. I'm trying to use your code: let isFileAvailable = remoteFileExistsAt(url: productImageUrl, completion:{ (data) in debugPrint((data)) }) i have always true. Super :) When I use wrong image url - I'm haven't response: false. Sometimes my serwer return error in text form: ErrorNot Found. – triff May 23 '18 at 06:10
  • 1
    The completion handler should be called if there is an error, not just when there is a response. – rmaddy May 23 '18 at 06:16
  • completion handler should be true or false – PPL May 23 '18 at 06:17
  • No, the completion handler will not be called if `response` is `nil`. You need to handle that case as well. – rmaddy May 23 '18 at 06:24
  • It's not working. I have this code: let productImageUrl : URL = URL(string: "https://www.udanewakacje.net/uploads/portal/atrakcje/mini_31801dfltybegjmotvwybhjwy6615457172X.jpg")! let checkLocalCopyFileIsAvailable = checkLocalFileCopyIsAvailable(fileName: productImageUrl) if checkLocalCopyFileIsAvailable == false { let isFileAvailable = remoteFileExistsAt(url: productImageUrl) { (result) in print(" Sprawdzam czy plik jest dostępny:\(result)") } }. – triff May 23 '18 at 06:35
  • I have answers: Sprawdzam czy plik jest dostępny: true Sprawdzam czy plik jest dostępny: true Sprawdzam czy plik jest dostępny: true Sprawdzam czy plik jest dostępny: true 2018-05-23 08:33:10.359695+0200 proj[21505:2320506] Task .<7> finished with error – triff May 23 '18 at 06:36
  • With this url: https://www.udanewakacje.net/uploads/portal/atrakcje/mini_31801dfltybegjmotvwybhjwy6615457172X.jpg the answer should always be negative – triff May 23 '18 at 06:37
  • What you want to say, I don't getting you, please update your question – PPL May 23 '18 at 07:07
  • @triff are you using bit.ly (Shorten) url? – PPL May 23 '18 at 09:08
  • yes. In app I use full url. If you open the shorten url - you see full url in yours browser :) – triff May 23 '18 at 09:22
  • @PPL No, it's still wrong. Add an `else` to the `if let`. Have the `else` call the completion handler with `false`. – rmaddy May 23 '18 at 14:16
  • That should now determine whether there is anything at that given URL or not but it doesn't indicate whether the URL contains content of a desired type. – rmaddy May 24 '18 at 04:48
0

It’s about getting data from an URL. If the data is nil the file don’t exist.

Getting data from an URL in Swift

Marc T.
  • 5,090
  • 1
  • 23
  • 40