0

I do some easy tasks with Firebase, set image url into json, download it and show it. But for some reason if the url contains umlauts e.g(ö, ä, ü etc..) the url is set to wrong section.

Edit: I gotta clarify that I do the percent encoding with the url. So it actually doesn't contain any umlauts.

So the url actually looks like this for example for Göteborgs Rapé Loose.png: https://firebasestorage.googleapis.com/v0/b/snuspedia.appspot.com/o/Go%CC%88teborgs%20Rape%CC%81%20Loose.png?alt=media&token=e8f2219b-d14e-46f6-a90f-ee21f912af6c

With umlaut it does like this:

enter image description here

And without umlauts it does correct like this:

enter image description here

This is how I do all these steps what I described:

if productsValue[indexPath.row]["productUrl"] != nil {
            cell.snusProductImageView!.kf_setImageWithURL(NSURL(string: productsValue[indexPath.row]["productUrl"] as! String)!)
        }
        else {
            let productImageref = productsValue[indexPath.row]["Products"] as! String

            let decomposedPath = productImageref.decomposedStringWithCanonicalMapping

            cell.snusProductImageView.image = nil
            cell.snusProductImageView.kf_showIndicatorWhenLoading = true

            FIRStorage.storage().reference().child("\(decomposedPath).png").downloadURLWithCompletion({(url, error)in

                FIRDatabase.database().reference().child("Snuses").child(decomposedPath).child("productUrl").setValue(url!.absoluteString)

                let resource = Resource(downloadURL: url!, cacheKey: decomposedPath)

                cell.snusProductImageView.kf_setImageWithURL(url)

            })

What is the problem, can you tell me? I've been searching the problem for a good week.

Frank van Puffelen
  • 565,676
  • 79
  • 828
  • 807
Tarvo Mäesepp
  • 4,477
  • 3
  • 44
  • 92
  • The URL shouldn't contain any umlauts in the first place; they should be percent encoded http://stackoverflow.com/questions/2742852/unicode-characters-in-urls – Pekka Aug 27 '16 at 07:58
  • I do the decomposedPath as you can see in the code. It will remove those. Actually in firebase they doesn't contain umlauts or unicode but are percent encoded – Tarvo Mäesepp Aug 27 '16 at 07:59
  • Looking in the manual, I don't think URL/percent encoding is what `decomposedStringWithCanonicalMapping` does. It looks like it's normalizing things like `ü` to `u` instead. Have you checked the resulting URL and tried to call it manually to see what result is returned? There's no errors from `downloadURLWithCompletion`? (iOS/Swift newbie here, so apologies if any of these are stupid questions.) – Pekka Aug 27 '16 at 08:02
  • 1
    Check my edit. I added the link. It looks like this actually. So no errors even manually. I can see the image. – Tarvo Mäesepp Aug 27 '16 at 08:06

1 Answers1

2

A URL cannot directly contain "Umlauts". To put it simple, a URL is a sequence of restricted ASCII characters.

That means, characters which are not allowed (e.g., ö, ä, ü etc.), need to be encoded properly. Since a URL is comprised of a couple of different components, each component may use a slightly different encoding. The details are covered here: Uniform Resource Identifier (URI): Generic Syntax.

In Cocoa and Cocoa Touch, there is a helper class, NSURLComponents which let you easily compose a proper URL string from the given original components in their natural character encoding.

Please note, that simply applying "percent encoding" to the whole improper encoded URL usually yields another incorrect encoded URL. Don't do that! Use NSURLComponents!

Edit:

Let me apply some - hopefully useful - comments to your code:

This expression is problematic:

  1. NSURL(string: productsValue[indexPath.row]["productUrl"] as! String)!

It would be preferable, to explicitly initialise a URL from the potentially missing value at index "productUrl" and include proper error handling. Converting strings to URLs is notoriously error prone.

Then

  1. let decomposedPath = productImageref.decomposedStringWithCanonicalMapping

This makes no sense, since per definition a URL string is composed of a restricted set of ASCII characters anyway.

So, in conclusion, check your given string which should become a URL, and ensure you can initialise a proper URL from it (as value of type URL) and also convert it back again correctly to a string, respectively to an array of ASCII characters, when sending it over a network.

Edit 2:

The code below demonstrates how you can utilise NSURLComponents to safely create a URL from a given base URL, a partial path component which refers to the endpoint and from a given set of parameters.

Copy/past this into playgrounds to try it out.

import Cocoa

extension String: ErrorType {}


// First, create a base URL and save it later for reuse:
// Caution: The given string must be properly encoded! But usually, the base address
// in native form should only use allowed characters anyway, so the encoded form 
// should be equal to the native form (otherwise, you have to encode it per component).
let urlBaseString = "https://firebasestorage.googleapis.com/v0/b/snuspedia.appspot.com/o"
guard let urlBase = NSURL(string: urlBaseString) else {
    throw "bad base URL"
}

print("Base URL path: \"\(urlBase.path!)\"")

// Get the current path and parameters using strings using their "native character set":
let itemPath = "Göteborgs Rapé Loose.png"
let params = ["alt": "media", "token": "e8f2219b-d14e-46f6-a90f-ee21f912af6c"]

// Create a partial URL components (representing a relative URL) with the given 
// path and query component:
let components = NSURLComponents() 
components.path = itemPath
components.queryItems = params.map { NSURLQueryItem(name: $0, value: $1) }

// Combine the base URL with the partial URL in order to get a fully specified URL:
guard let url = components.URLRelativeToURL(urlBase) else {
    throw "Failed to create final URL"
}
print("URL: \(url.absoluteString)")

Output:

URL: https://firebasestorage.googleapis.com/v0/b/snuspedia.appspot.com/G%C3%B6teborgs%20Rap%C3%A9%20Loose.png?alt=media&token=e8f2219b-d14e-46f6-a90f-ee21f912af6c

Community
  • 1
  • 1
CouchDeveloper
  • 18,174
  • 3
  • 45
  • 67