0

As I don't have enough rep points for comment for this question URL Encoding swift IOS, I created a new question. I would like to receive feedback on making it more swifty for use cases like this one.

My understanding of OP question is inside API response or from data, there is multiple links of URLs for image, with possibility of different host domains.

In such cases, the host URL could be first retrieved like in this answer. In similar way, the path can also be retrieved separately.

The path can be encoded like as below and concat back to host string later.

addingPercentEncoding(withAllowedCharacters: .urlHostAllowed)

This is what I initially tried out in playground.

import Foundation

extension String {
    var encoded: String? {
        return self.addingPercentEncoding(withAllowedCharacters: .urlPathAllowed)
    }
}

let urlStrings:[String] = ["https://example.com/test.jpg"
                           "https://example.cc/test2.jpg",
                           "https://example.dev.cc/test3.jpg"]

var encodedUrlStrings: [String] = []

urlStrings.forEach { urlString in
    print(urlString)
    guard let url = URL(string: urlString),
            let domain = url.host,
            let encodedPath = url.path.encoded else { return }
    
    let encodedUrlString = domain + encodedPath
    encodedUrlStrings.append(encodedUrlString)
}
encodedUrlStrings.count
encodedUrlStrings.forEach { print($0) }

But the weird thing I notice from OP's question is the url itself should not be already including character like space or any unicode character.

https://ftximages.apk.in/test Fretailer_Point-6685.jpg

For such string, converting into URL will always return nil with URL(String:) method. Same result for using URLComponents as well as the characters in path are still not usable in URL. So this need to make more agreements with backedn dev or anyone who's sending such URL string without encoded characters.

Just in case the backend dev is making a fuss, following codes will gives example of encoded URL strings.

String extension from @Claudio's answer.

import Foundation

extension String {
    var encoded: String? {
        return self.addingPercentEncoding(withAllowedCharacters: .urlPathAllowed)
    }
}

let urlStrings:[String] = ["https://example.com.cc/folder/test.jpg",
                           "https://example.com/test.jpg",
                           "https://Ftximages.apk.in/test Fretailer_Point-6685.jpg",
                           "https://example.com/원 더 우먼.jpg",
                           "https://example.dev.cc/刺客聶隱娘-6685.jpg",
                           "https://example.cc/बाजीराव मस्तानी.jpg"]

var encodedUrlStrings: [String] = []

func encodeURL(scheme: String, host: String, path: String) -> String? {
    var components = URLComponents()
    components.scheme = scheme
    components.host = host
    components.path = path
    
    return components.url?.absoluteString ?? URL(string: "\(scheme)://\(host)/\(path)")?.absoluteString
}

func encodeWeirdUrlString(_ urlString: String) -> String? {
    var urlSplitStrings = urlString.components(separatedBy: ["/"])
    urlSplitStrings.removeAll(where: { $0.isEmpty })
    guard  urlSplitStrings.indices.contains(0), urlSplitStrings.indices.contains(1) else { return nil }
    
    let scheme = String(urlSplitStrings[0].dropLast())
    let host = urlSplitStrings[1]
    
    urlSplitStrings.remove(at: 1)
    urlSplitStrings.remove(at: 0)
    
    guard let path = urlSplitStrings.joined(separator: "/").encoded else { return nil}
    
    let encodedUrlString = encodeURL(scheme: scheme, host: host, path: path)
    
    return encodedUrlString
}

urlStrings.forEach { urlString in
    print(urlString)
    guard let url = URL(string: urlString),
          let scheme = url.scheme,
          let host = url.host,
          let encodedPath = url.path.encoded,
          let encodedUrlString = encodeURL(scheme: scheme, host: host, path: encodedPath) else {
              
              if let encodedUrlString = encodeWeirdUrlString(urlString) {
                  encodedUrlStrings.append(encodedUrlString)
              }
              return
          }
    
    encodedUrlStrings.append(encodedUrlString)
}

encodedUrlStrings.count
encodedUrlStrings.forEach { print($0) }

Are there any improvements to make this solution more swifty?

Skron31
  • 11
  • 1
  • 2
  • If your code works then the question is rather off-topic for Stack Overflow. You may want to try Code Review instead if you want to ask for how to improve it (but please first check if your question fits their posting requirements). – Eric Aya Nov 04 '21 at 12:15
  • @EricAya, thanks for notifying. I have 2 questions actually for my post. One is code review, so I will check Code Review post requirement. Second is I would like to ask if string itself is not correct URL, converting in Swift language will always return nil. I would like to ask if there is workaround for this kind of situation. If I edit my question, is it still off-topic? – Skron31 Nov 04 '21 at 12:33
  • The biggest misunderstanding about URL encoding is that it does not encode URLs. Instead, it encodes parts of a URL, usually query parameters. If you have a URL, you already have a URL. There is nothing to encode. The main problem of the above code is that is unclear what it is trying to achieve. So add documentation. And improve the naming. Most likely `encodeWeirdUrlString` should rather be called `tryToFixInvalidUrl`. And `encoded` should be called `urlPathElementEncoded`. And you probably want to add a separate version for query parameters. – Codo Nov 04 '21 at 12:40
  • Thanks for pointing out for code improvements. I agree with encoding part as well. Actually I would like to add this a comment to the post I mentioned in the question, but my rep points are not enough. Inside the original question, OP was encoding the entire url string, which make "https://" into "https%3A%2F%2". So for path, query and fragment, there would require separate versions to cover it all. – Skron31 Nov 04 '21 at 12:49
  • The documentation and/or agreement with person who provided the json response/data is also important as well, imo. If url strings are already correct, there is no need to encode from mobile app side. – Skron31 Nov 04 '21 at 12:49
  • @Skron31 that's why you should use URLComponents when composing your URL – Leo Dabus Nov 04 '21 at 14:03

0 Answers0