NSUTF8StringEncoding in NSURLConnection führt zu fatal error

Diese Seite verwendet Cookies. Durch die Nutzung unserer Seite erklären Sie sich damit einverstanden, dass wir Cookies setzen. Weitere Informationen

  • NSUTF8StringEncoding in NSURLConnection führt zu fatal error

    Ich frage mittels NSURLConnection eine URL ab und erwarte einen String retour. Der folgende Code funktioniert eigentlich ganz wunderbar...

    Quellcode

    1. ​let request = NSURLRequest(URL: NSURL(string: "http://www.google.de"))
    2. NSURLConnection.sendAsynchronousRequest(request, queue: NSOperationQueue.mainQueue(), completionHandler: {
    3. response, data, error in
    4. let htmlResult = NSString(data: data, encoding: NSUTF8StringEncoding)


    ... solange ich mit NSASCIIStringEncoding arbeite. Das Problem damit ist, dass im zurückgegebenen String Umlaute oder Sonderzeichen wie ein Leerzeichen nach dem Muster   übergeben werden. Meine Vermutung war, dass NSUTF8StringEncoding hier Abhilfe schafft. Jedoch erhalte ich beim Versuch, den String im Anschluss weiterzuverarbeiten, immer folgende Fehlermeldung in der Konsole:

    ​fatal error: Can't unwrap Optional.None

    Woran liegt das?

    Danke vorab und viele Grüße
  • macmoonshine schrieb:

    Genau genommen ist sogar das ASCII-Encoding ein Fehler, weil UTF-8 die Standardkodierung ist. Hier findest Du mehr zum Thema URLs erstellen.


    URLs an sich DÜRFEN nur ASCII enthalten.
    aber hier gehts ja um den content. der KANN ASCII oder auch UTF8 oder auch sonstwas sein.
    entweder es steht im document (bis dahin sollte also kein non-ascii-zeichen vorkommen) oder man muss raten.
    google scheint aber so nett zu sein und reines ASCII zurückzuschicken.
  • gritsch schrieb:

    1.   hat nix mit utf8 zu tun.


    Okay, danke. Gibt es demnach auch keine Möglichkeit, diese Zeichen-Entitäten mittels "Boardmitteln" zu entfernen?

    Im Hinblick auf die Tatsache, dass der Content wie du schreibst sowohl ASCII als auch UTF8 sein kann - wie geht man dbzgl. idealerweise vor, wenn es um die Abfrage von URLs geht? Theoretisch müsste ich mir den Code der Seite einmal unkodiert(?) anschauen bis zu dem Punkt, an dem ich etwas wie ​<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> finde, oder?
  • mrtn.lxo schrieb:

    gritsch schrieb:

    1. &nbsp; hat nix mit utf8 zu tun.


    Okay, danke. Gibt es demnach auch keine Möglichkeit, diese Zeichen-Entitäten mittels "Boardmitteln" zu entfernen?

    Im Hinblick auf die Tatsache, dass der Content wie du schreibst sowohl ASCII als auch UTF8 sein kann - wie geht man dbzgl. idealerweise vor, wenn es um die Abfrage von URLs geht? Theoretisch müsste ich mir den Code der Seite einmal unkodiert(?) anschauen bis zu dem Punkt, an dem ich etwas wie ​<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> finde, oder?


    ich verwende meist libxml (ist bei osx und ios an bord).

    normalerweise kennt man die encoding weil man ja auch das format der zurückgegeben daten kennen sollte.
    man verwendet also meist eine dokumentierte "schnittstelle". ist dem nicht so, sollte man sich fragen ob man das überhaupt aus rechtlicher sicht darf.
  • mrtn.lxo schrieb:

    Quellcode

    1. let request = NSURLRequest(URL: NSURL(string: "http://www.google.de"))
    2. NSURLConnection.sendAsynchronousRequest(request, queue: NSOperationQueue.mainQueue(), completionHandler: {
    3. response, data, error in
    4. let htmlResult = NSString(data: data, encoding: NSUTF8StringEncoding)


    ... solange ich mit NSASCIIStringEncoding arbeite. Das Problem damit ist, dass im zurückgegebenen String Umlaute oder Sonderzeichen wie ein Leerzeichen nach dem Muster &nbsp; übergeben werden. Meine Vermutung war, dass NSUTF8StringEncoding hier Abhilfe schafft. Jedoch erhalte ich beim Versuch, den String im Anschluss weiterzuverarbeiten, immer folgende Fehlermeldung in der Konsole:

    fatal error: Can't unwrap Optional.None

    Woran liegt das?

    Das liegt daran, dass

    let htmlResult = NSString(data: data, encoding: NSUTF8StringEncoding)

    auch nil zurückgeben kann, was hier offensichtlich passiert. In Swift bedeutet das, dass du einen Optional-Wert zurückbekommst. Du musst also deine Variable als Optional deklarieren:

    let htmlResult: NSString? = NSString(data: data, encoding: NSUTF8StringEncoding)

    Hach ja, diese Type Inference von Swift macht das alles ja sooooo schön lesbar.
  • Michael schrieb:

    Das liegt daran, dass

    let htmlResult = NSString(data: data, encoding: NSUTF8StringEncoding)

    auch nil zurückgeben kann, was hier offensichtlich passiert. In Swift bedeutet das, dass du einen Optional-Wert zurückbekommst. Du musst also deine Variable als Optional deklarieren:

    let htmlResult: NSString? = NSString(data: data, encoding: NSUTF8StringEncoding)

    Hach ja, diese Type Inference von Swift macht das alles ja sooooo schön lesbar.


    Tut sie auch. Die explizite Deklaration ist hier ja auch nicht nötig, sondern man muß sich nur im klaren darüber sein, daß da ein Optional zurückgegeben wird, was durch die Fehlermeldung ja aber auch sofort klar ist, wenn man versucht, die Rückgabe ohne vorheriges Auspacken direkt zu benutzen. Da der Compiler selbst darauf aufpaßt, ist es nicht unbedingt notwendig, sich nochmal extra durch explizite Deklarations-Klimmzüge zu vergewissern.

    Was die Frage eigentlich nur klarmacht, ist, daß man sich wie bei jeder anderen Sprache halt erst mal an die speziellen Sprachkonstrukte gewöhnen muß – und dazu gehört auch, daß man sich daran gewöhnen muß, was die entsprechenden Fehlermeldungen eigentlich im Zusammenhang bedeuten. Wenn man das ein bißchen intus hat, ist sehr schnell klar, was da jeweils passiert ist, aber ein bißchen Zeit kann das schon brauchen.
  • RegExpressive schrieb:

    Michael schrieb:

    Das liegt daran, dass

    let htmlResult = NSString(data: data, encoding: NSUTF8StringEncoding)

    auch nil zurückgeben kann, was hier offensichtlich passiert. In Swift bedeutet das, dass du einen Optional-Wert zurückbekommst. Du musst also deine Variable als Optional deklarieren:

    let htmlResult: NSString? = NSString(data: data, encoding: NSUTF8StringEncoding)

    Hach ja, diese Type Inference von Swift macht das alles ja sooooo schön lesbar.


    RegExpressive schrieb:

    Tut sie auch.

    Nein, tut sie nicht.

    RegExpressive schrieb:

    Die explizite Deklaration ist hier ja auch nicht nötig,

    Ja, stimmt (hab mich da vom Playground irritieren lassen), aber gerade durch das Weglassen wird der Code nicht eindeutig verständlich.

    RegExpressive schrieb:

    sondern man muß sich nur im klaren darüber sein, daß da ein Optional zurückgegeben wird,

    worüber man sich wegen der Type Inference nur durch einen Blick in die Dokumentation klar werden kann. Mit expliziter Deklaration weiß ich auch ohne Blick in die Dokumentation, was ich zu tun habe.

    RegExpressive schrieb:

    was durch die Fehlermeldung ja aber auch sofort klar ist, wenn man versucht, die Rückgabe ohne vorheriges Auspacken direkt zu benutzen. Da der Compiler selbst darauf aufpaßt, ist es nicht unbedingt notwendig, sich nochmal extra durch explizite Deklarations-Klimmzüge zu vergewissern.

    Verlass dich da mal nicht zu sehr auf den Compiler:

    Quellcode

    1. import Foundation
    2. var aString = "Hallöchen"
    3. var data = aString.dataUsingEncoding(NSMacOSRomanStringEncoding, allowLossyConversion: false)
    4. var foo = NSString(data: data, encoding: NSUTF8StringEncoding)
    5. var bar = foo.stringByAppendingString(" Welt!")
    6. println("\(bar)"
    7. println("\(foo)"

    Dieser Code compiliert einwandfrei. Und nun sag mir mal, an welcher Stelle das Progrämmchen mit einem EXC_BAD_ACCESS abschmiert.

    RegExpressive schrieb:

    Was die Frage eigentlich nur klarmacht, ist, daß man sich wie bei jeder anderen Sprache halt erst mal an die speziellen Sprachkonstrukte gewöhnen muß – und dazu gehört auch, daß man sich daran gewöhnen muß, was die entsprechenden Fehlermeldungen eigentlich im Zusammenhang bedeuten. Wenn man das ein bißchen intus hat, ist sehr schnell klar, was da jeweils passiert ist, aber ein bißchen Zeit kann das schon brauchen.

    Ja, aber wenn man schon eine neue Programmiersprache entwickelt, muss man da nicht auch neue Fallen einbauen.
  • Michael schrieb:

    Dieser Code compiliert einwandfrei. Und nun sag mir mal, an welcher Stelle das Progrämmchen mit einem EXC_BAD_ACCESS abschmiert.

    Ich weiß, das galt nicht mir.
    Aber üben schadet ja nicht:

    Quellcode

    1. var bar = foo.stringByAppendingString(" Welt!")

    Es wird stringByAppendingString an nil gesendet, und da eine Rückgabe erwartet wird, führt das zu einem EXC_BAD_ACCESS.
    «Applejack» "Don't you use your fancy mathematics to muddle the issue!"

    Iä-86! Iä-64! Awavauatsh fthagn!

    kmr schrieb:

    Ach, Du bist auch so ein leichtgläubiger Zeitgenosse, der alles glaubt, was irgendwelche Typen vor sich hin brabbeln. :-P
  • Michael schrieb:

    RegExpressive schrieb:

    Michael schrieb:

    Das liegt daran, dass

    let htmlResult = NSString(data: data, encoding: NSUTF8StringEncoding)

    auch nil zurückgeben kann, was hier offensichtlich passiert. In Swift bedeutet das, dass du einen Optional-Wert zurückbekommst. Du musst also deine Variable als Optional deklarieren:

    let htmlResult: NSString? = NSString(data: data, encoding: NSUTF8StringEncoding)

    Hach ja, diese Type Inference von Swift macht das alles ja sooooo schön lesbar.


    RegExpressive schrieb:

    Tut sie auch.

    Nein, tut sie nicht.


    Doch, durchaus. In diesem frühen Stadium bist Du nur noch nicht an die Funktionsweise der Sprache gewöhnt, weshalb Du da einfach noch unsicher bist. Mit zunehmender Kompetenz in der Sprache wird dann immer klarer werden, an welchen Stellen explizite Angaben tatsächlich noch Sinn machen, weil wirklich ein wesentliches Risiko von Mißverständnissen besteht, und wo explizite Deklarationen einfach überflüssig sind.

    Du verschachtelst ja auch in Objective-C routinemäßig Methoden-Aufrufe, wo die inneren irgendwelche Typen zurückgeben, die Du ohne Deklaration dieses Typs einfach kommentarlos direkt in eine andere reinsteckst.

    Swift erlaubt effektiv einfach bloß genau dasselbe über mehrere Zeilen hinweg mit sprechend benannten Zwischenvariablen und nicht nur Expression-Verschachtelungsmonster, aber dabei ist es zumindest in den meisten Fällen immer noch genauso überflüssig, für solche durchlaufenden Werte jedesmal unbedingt extra die Typen deklarieren zu müssen.

    Eine Variable (inklusive let-Konstanten) ist einfach nur ein Container für einen wie auch immer getypten Wert, genauso wie das innerhalb von Expressions schon immer implizit gemacht wurde, dort aber zwangsläufig anonym durch direkte Einsetzung, was die Sache aber häufig kein bißchen übersichtlicher oder lesbarer macht.

    Michael schrieb:

    RegExpressive schrieb:

    sondern man muß sich nur im klaren darüber sein, daß da ein Optional zurückgegeben wird,

    worüber man sich wegen der Type Inference nur durch einen Blick in die Dokumentation klar werden kann. Mit expliziter Deklaration weiß ich auch ohne Blick in die Dokumentation, was ich zu tun habe.


    Nein. In der Regel wird Dir der Compiler sagen, wenn es nicht paßt, genauso wie wenn Du versuchst, einen Funktionsaufruf kommentarlos in einen anderen einzusetzen. Das ist effektiv dasselbe, nur in Swift verallgemeinert und nicht auf einzelne Expressions beschränkt.

    Michael schrieb:

    Verlass dich da mal nicht zu sehr auf den Compiler:

    Quellcode

    1. import Foundation
    2. var aString = "Hallöchen"
    3. var data = aString.dataUsingEncoding(NSMacOSRomanStringEncoding, allowLossyConversion: false)
    4. var foo = NSString(data: data, encoding: NSUTF8StringEncoding)
    5. var bar = foo.stringByAppendingString(" Welt!")
    6. println("\(bar)")
    7. println("\(foo)")

    Dieser Code compiliert einwandfrei. Und nun sag mir mal, an welcher Stelle das Progrämmchen mit einem EXC_BAD_ACCESS abschmiert.


    (Ich habe mal die fehlenden Klammern in Deinem Code ergänzt, damit er funktioniert.)

    Ganz einfach: Ganz normal im Debugger ausführen, der Dir zeigt, wo der Laufzeitfehler(!) aufgetreten ist. In diesem Fall ist es die letzte Zeile (also println("\(foo)")):

    fatal error: unexpectedly found nil while unwrapping an Optional value

    Die Ursache ist also in der Tat wie oben schon gesagt, daß foo nil ist. Da ist nichts groß Mysteriöses dabei.

    Das kann der Compiler hier nicht vorab wissen, weil der Objective-C-Aufruf anders als ein Swift-Aufruf nicht sauber deklariert, was da zurückkommen kann und was nicht. Deshalb muß man beim Reinmischen von Objective-C nochmal zusätzlich aufpassen, aber letztlich auch nur so wie in Objective-C selber ja auch schon immer.

    Michael schrieb:

    RegExpressive schrieb:

    Was die Frage eigentlich nur klarmacht, ist, daß man sich wie bei jeder anderen Sprache halt erst mal an die speziellen Sprachkonstrukte gewöhnen muß – und dazu gehört auch, daß man sich daran gewöhnen muß, was die entsprechenden Fehlermeldungen eigentlich im Zusammenhang bedeuten. Wenn man das ein bißchen intus hat, ist sehr schnell klar, was da jeweils passiert ist, aber ein bißchen Zeit kann das schon brauchen.

    Ja, aber wenn man schon eine neue Programmiersprache entwickelt, muss man da nicht auch neue Fallen einbauen.


    Wo ist da eine "Falle" speziell in Swift? Du bindest Objective-C-Code ein, und der hat immer noch dieselben Komplikationen, die er schon immer hatte.
  • RegExpressive schrieb:

    Michael schrieb:

    RegExpressive schrieb:

    Michael schrieb:

    Das liegt daran, dass

    let htmlResult = NSString(data: data, encoding: NSUTF8StringEncoding)

    auch nil zurückgeben kann, was hier offensichtlich passiert. In Swift bedeutet das, dass du einen Optional-Wert zurückbekommst. Du musst also deine Variable als Optional deklarieren:

    let htmlResult: NSString? = NSString(data: data, encoding: NSUTF8StringEncoding)

    Hach ja, diese Type Inference von Swift macht das alles ja sooooo schön lesbar.


    RegExpressive schrieb:

    Tut sie auch.

    Nein, tut sie nicht.


    Doch, durchaus. In diesem frühen Stadium bist Du nur noch nicht an die Funktionsweise der Sprache gewöhnt, weshalb Du da einfach noch unsicher bist. Mit zunehmender Kompetenz in der Sprache wird dann immer klarer werden, an welchen Stellen explizite Angaben tatsächlich noch Sinn machen, weil wirklich ein wesentliches Risiko von Mißverständnissen besteht, und wo explizite Deklarationen einfach überflüssig sind.

    Du verschachtelst ja auch in Objective-C routinemäßig Methoden-Aufrufe, wo die inneren irgendwelche Typen zurückgeben, die Du ohne Deklaration dieses Typs einfach kommentarlos direkt in eine andere reinsteckst.

    Swift erlaubt effektiv einfach bloß genau dasselbe über mehrere Zeilen hinweg mit sprechend benannten Zwischenvariablen und nicht nur Expression-Verschachtelungsmonster, aber dabei ist es zumindest in den meisten Fällen immer noch genauso überflüssig, für solche durchlaufenden Werte jedesmal unbedingt extra die Typen deklarieren zu müssen.

    Eine Variable (inklusive let-Konstanten) ist einfach nur ein Container für einen wie auch immer getypten Wert, genauso wie das innerhalb von Expressions schon immer implizit gemacht wurde, dort aber zwangsläufig anonym durch direkte Einsetzung, was die Sache aber häufig kein bißchen übersichtlicher oder lesbarer macht.

    Michael schrieb:

    RegExpressive schrieb:

    sondern man muß sich nur im klaren darüber sein, daß da ein Optional zurückgegeben wird,

    worüber man sich wegen der Type Inference nur durch einen Blick in die Dokumentation klar werden kann. Mit expliziter Deklaration weiß ich auch ohne Blick in die Dokumentation, was ich zu tun habe.


    Nein. In der Regel wird Dir der Compiler sagen, wenn es nicht paßt, genauso wie wenn Du versuchst, einen Funktionsaufruf kommentarlos in einen anderen einzusetzen. Das ist effektiv dasselbe, nur in Swift verallgemeinert und nicht auf einzelne Expressions beschränkt.

    Michael schrieb:

    Verlass dich da mal nicht zu sehr auf den Compiler:

    Quellcode

    1. import Foundation
    2. var aString = "Hallöchen"
    3. var data = aString.dataUsingEncoding(NSMacOSRomanStringEncoding, allowLossyConversion: false)
    4. var foo = NSString(data: data, encoding: NSUTF8StringEncoding)
    5. var bar = foo.stringByAppendingString(" Welt!")
    6. println("\(bar)"
    7. println("\(foo)")

    Dieser Code compiliert einwandfrei. Und nun sag mir mal, an welcher Stelle das Progrämmchen mit einem EXC_BAD_ACCESS abschmiert.


    Ganz einfach: Ganz normal im Debugger ausführen, der Dir zeigt, wo der Laufzeitfehler(!) aufgetreten ist. In diesem Fall ist es die letzte Zeile (also println("\(foo)")):

    fatal error: unexpectedly found nil while unwrapping an Optional value

    Die Ursache ist also in der Tat wie oben schon gesagt, daß foo nil ist. Da ist nichts groß Mysteriöses dabei.

    Das kann der Compiler hier nicht vorab wissen, weil der Objective-C-Aufruf anders als ein Swift-Aufruf nicht sauber deklariert, was da zurückkommen kann und was nicht. Deshalb muß man beim Reinmischen von Objective-C nochmal zusätzlich aufpassen, aber letztlich auch nur so wie in Objective-C selber ja auch schon immer.

    Michael schrieb:

    RegExpressive schrieb:

    Was die Frage eigentlich nur klarmacht, ist, daß man sich wie bei jeder anderen Sprache halt erst mal an die speziellen Sprachkonstrukte gewöhnen muß – und dazu gehört auch, daß man sich daran gewöhnen muß, was die entsprechenden Fehlermeldungen eigentlich im Zusammenhang bedeuten. Wenn man das ein bißchen intus hat, ist sehr schnell klar, was da jeweils passiert ist, aber ein bißchen Zeit kann das schon brauchen.

    Ja, aber wenn man schon eine neue Programmiersprache entwickelt, muss man da nicht auch neue Fallen einbauen.


    Wo ist da eine "Falle" speziell in Swift? Du bindest Objective-C-Code ein, und der hat immer noch dieselben Komplikationen, die er schon immer hatte.


    und warum ist "bar" plötzlich nicht mehr nil wenn "foo" nil ist?

    edit: was zum teufel ist mit der quote-funktion hier los?
  • gritsch schrieb:

    und warum ist "bar" plötzlich nicht mehr nil wenn "foo" nil ist?


    Gute Frage; Aber auch hier hilft der Debugger:

    bar Swift.ImplicitlyUnwrappedOptional<Swift.String> nil None

    (Übrigens von println ausgegeben als nil.)

    und:

    foo Foundation.NSString 0x0000000000000000 0x0000000000000000

    Hier zeigen sich offenbar die Feinheiten der API-Bindings.

    gritsch schrieb:

    edit: was zum teufel ist mit der quote-funktion hier los?


    Was tut die denn bei Dir?

    (Ich hatte hier meinen ganzen Sermon oben mal abgeschnitten.)
  • ich versteh den ganzen mist eh nicht.
    was genau ist denn das problem dass ein pointer nil sein kann oder eben auf eine instanz zeigen kann (oder sonstwohin im speicher)?
    messages an nil sind ja kein problem (wir sind ja nicht bei c++)...
    also warum das ganze unrwapping etc?
    man hat ja nichtmal die sicherheit dass da wirklich was drinsteckt (siehe beispiel)
  • RegExpressive schrieb:

    Ganz einfach: Ganz normal im Debugger ausführen, der Dir zeigt, wo der Laufzeitfehler(!) aufgetreten ist. In diesem Fall ist es die letzte Zeile (also println("\(foo)")):

    Och, einfach ausführen und gucken wo es kracht kann ja jeder. Ich dachte ja, da Swift ja soooo schön lesbar ist, hättest du die Absturzstelle nur anhand des Codes nennen können. Swift ist wohl doch nicht soooo schön lesbar.

    RegExpressive schrieb:

    Die Ursache ist also in der Tat wie oben schon gesagt, daß foo nil ist. Da ist nichts groß Mysteriöses dabei.

    Nur warum stürzt das Programm erst bei der letzten Zeile ab?

    RegExpressive schrieb:

    Das kann der Compiler hier nicht vorab wissen, weil der Objective-C-Aufruf anders als ein Swift-Aufruf nicht sauber deklariert, was da zurückkommen kann und was nicht. Deshalb muß man beim Reinmischen von Objective-C nochmal zusätzlich aufpassen, aber letztlich auch nur so wie in Objective-C selber ja auch schon immer.

    Ja, das erzähl mal den ganzen Einsteigern, die Objective-C noch nie gesehen haben.

    RegExpressive schrieb:

    Wo ist da eine "Falle" speziell in Swift? Du bindest Objective-C-Code ein, und der hat immer noch dieselben Komplikationen, die er schon immer hatte.

    Ich weise zwei Variablen jeweils das Ergebnis einer Objective-C Methode zu und lasse Type Inference entscheiden welchen Typ die dann haben. Wenn ich jetzt mal den Compiler spiele, würde ich so aus dem Bauch heraus für foo den Typ NSString! nehmen und für bar auch, weil der Wert für bar ja auf foo basiert. Schaut man aber mal in die Dokumentation, stellt man fest, das bar ein String! wird. Oh, eine Objective-C Methode liefert auf einmal ein Swift-Objekt zurück! Zack, Falle hat zugeschnappt, weil Type Inference das alles verschleiert. Die Komplikation kommt hier nicht von Objective-C.
    Und wenn man dann noch mal den Debugger anschmeißt, stellt man außerdem fest, dass foo ein NSString wird, also gar kein Optional, obwohl da auch nil zurückgeliefert werden kann. Wie war das? Variablen dürfen nicht nil sein, außer man deklariert sie als Optional? Demnach müsste das Programm sogar schon bei der Initialisierung von foo abschmieren.