NSNumberformatter in einer Tools Klasse

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

  • NSNumberformatter in einer Tools Klasse

    Hallo, bin neu hier (und bei der xcode Programmierungen) und habe folgendes Problem:

    Ich habe mir eine Klasse 'Tools' angelegt mit den folgenden Methoden,
    um den NSNumberformatter aus jedem Viewcontroller aufrufen zu können:

    Quellcode

    1. ​-(NSNumber*) numberFromString :(NSString*)eingabe
    2. {
    3. NSNumberFormatter *formatter = [[NSNumberFormatter alloc] init];
    4. [formatter setLocale:[NSLocale currentLocale]];
    5. formatter.numberStyle = NSNumberFormatterDecimalStyle;
    6. NSNumber *number = [formatter numberFromString:eingabe]; // Formatierte Zahl als Number
    7. return number;
    8. }
    9. -(NSString*) stringFromNumber :(NSNumber*)eingabe :(NSInteger)d1 :(NSInteger)d2
    10. {
    11. NSNumberFormatter *formatter = [[NSNumberFormatter alloc] init];
    12. [formatter setLocale:[NSLocale currentLocale]];
    13. formatter.numberStyle = NSNumberFormatterDecimalStyle;
    14. formatter.maximumFractionDigits = d2;
    15. formatter.minimumFractionDigits = d1;
    16. NSString *string = [formatter stringFromNumber: eingabe]; // Formatierte Zahl als String
    17. return string;
    18. }
    Alles anzeigen


    Aufgerufen werden die Methoden dann nach beenden der Eingabe in einem Textfeld für z.B. einen Betrag:

    Quellcode

    1. ​- (IBAction)tf02rechnung_EditingDidEnd:(id)sender // Verlassen Rechnung
    2. {
    3. _tf02rechnung.backgroundColor = nil; // HintergrundFarbe wieder auf Default
    4. rechnung = [mytool numberFromString:_tf02rechnung.text]; // Eingabe in Zahl umwandeln
    5. _tf02rechnung.text = [mytool stringFromNumber:rechnung :2 :2]; // Formatierte Zahl als String in Textfeld
    6. }


    Das funktioniert eigentlich auch gut, nur bekomme ich in der Zeile

    Quellcode

    1. ​ _tf02rechnung.text = [mytool stringFromNumber:rechnung :2 :2]; // Formatierte Zahl als String in Textfeld

    immer die Warnung: incompatible pointer types sending 'NSNumber*' to parameter of type 'NSString*'[/b]

    Klar sende ich den umgewandelten NSNumber und möchte den umgewandelten String zurückbekommen.
    Soll ich die Warnung ignorieren ? Oder was mache ich hier falsch ?

    mfg Paulsche
    MfG. Bernhard
    (hb-mobilesoft.de)
  • Du hantierst da mit lauter Variablen rum wo wir nicht wissen wo die herkommen. Was ist rechung überhaupt?

    Methodenparameter ohne Namen sowas macht man einfach nicht. Das sehe ich jetzt schon zum zweiten mal in den letzten Wochen. In welchem gerade beliebten bekloppten Tutorial steht das eigentlich?

    solche Methode würde ich entweder als Kategorie zu NSString machen oder als klasenmethoden. Damit erspare ich mir das unnötig instanzieren.

    Gruss

    Claus
    2 Stunden Try & Error erspart 10 Minuten Handbuchlesen.

    Pre-Kaffee-Posts sind mit Vorsicht zu geniessen :)
  • Hallo Claus,

    danke für Deine Antwort. Manches erschliesst sich mir noch nicht so, habe vorher mit Basic4Android programmiert,
    hier funktioniert es anders wie ich gemerkt habe.

    Mich würde die grundsätzliche richtige Vorgehensweise für mein Projekt schon sehr weiterhelfen,
    das Eingeben von Daten (Hauptsächlich Dezimalzahlen) in Viewcontroller in Textfelder,
    die Daten sollen dann in CoreData gespeichert werden.

    Die notwendigen Variablen z.B. Rechnung habe ich am Anfang im Viewcontroller-Klasse vor der implementation
    definiert, um damit in jeder Methode der Klasse damit rechnen zu können, das wären praktisch die Numerischen Werte
    aus den Textfeldern.

    Nun vermute ich auch dass dies der falsche Weg ist, vielleicht kannst Du mir ganz grob beschreiben wie ich die APP aufbauen müsste,
    ich wäre Dir sehr dankbar.

    Hab zwar zwei Bücher und ein Videotraining, aber die Beispiele treffen nicht so auf meine APP zu.

    Meine APP ist eine Spritverbrauchs-APP, Ich möchte einfach Eingabemasken für Fahrzeugdaten und Tankdaten (km-Stand,Liter,Literpreis usw.) , mit den Eingaben sollen Berechnungen in einer Methode gemacht werden,
    die von mehreren Viewcontrollern aufgerufen werden können sollte.

    Es ist momentan sehr mühsam für mich den richtigen Anfang zu finden und ich fühle mich wie ein totaler Anfänger,
    obwohl ich 3 erfolgreiche APPs im Google-Store laufen habe. Aber ich denke wenn ich die Grundsatzprobleme gemeistert habe,
    dann komme ich voran.
    MfG. Bernhard
    (hb-mobilesoft.de)
  • Wie bereits grätsch richtig sagte, ergibt diese "Toolsklasse" überhaupt keinen Sinn. Wenn du in einer Instanzmethode nicht self (oder gleich eine Instanzvariable) benutzt, ist das ein Code-Smell. Instanzmethoden sind dazu da, auf den State des Instanzobjektes zuzugreifen. Wenn das nicht notwendig ist, warum sind sie dann Methoden der Instanz einer bestimmten Klasse?

    Darüber hinaus sind unbenannte Parameter in Objective-C sinnfrei.

    Vielleicht solltest du dich von deiner bisherigen Programmiersprache lösen
    Es hat noch nie etwas gefunzt. To tear down the Wall would be a Werror!
    25.06.2016: [Swift] gehört zu meinen *Favorite Tags* auf SO. In welcher Bedeutung von "favorite"?
  • Paulsche schrieb:

    Hab zwar zwei Bücher und ein Videotraining, aber die Beispiele treffen nicht so auf meine APP zu.
    Selbstverständlich treffen die auf deine App zu, da dort sicherlich benannte Parameter verwendet werden. Wieso machst du es also anders?

    Wenn es ein Buch gäbe, welches genau die Sourcen deiner App enthielten, bräuchtest du sie ja nicht mehr zu programmieren.
    Es hat noch nie etwas gefunzt. To tear down the Wall would be a Werror!
    25.06.2016: [Swift] gehört zu meinen *Favorite Tags* auf SO. In welcher Bedeutung von "favorite"?
  • Amin Negm-Awad schrieb:

    Wie bereits grätsch richtig sagte, ergibt diese "Toolsklasse" überhaupt keinen Sinn. Wenn du in einer Instanzmethode nicht self (oder gleich eine Instanzvariable) benutzt, ist das ein Code-Smell. Instanzmethoden sind dazu da, auf den State des Instanzobjektes zuzugreifen. Wenn das nicht notwendig ist, warum sind sie dann Methoden der Instanz einer bestimmten Klasse?

    Darüber hinaus sind unbenannte Parameter in Objective-C sinnfrei.

    Vielleicht solltest du dich von deiner bisherigen Programmiersprache lösen


    Ok, danke. Wenn ich es richtig verstanden habe, sollte man hauptsächlich mit Objekten arbeiten, nicht mit Variablen die in einer ganzen Klasse gültig wären.
    Ok, wo definiere ich meine Tools-Methoden die ich immer wieder mal brauche wie z.B. NSNumberformatter wo ich die benötigten Parameter mitgebe
    und den umgewandelten Wert zurücbekomme ? Ich dachte da wäre eine Klasse wie z.B. Tools das richtige. Sonst muss ich ja in jeder Klasse diese Methode
    einfügen und das wäre ja nicht sinnvoll. Oder wäre für sowas eine Klassenmethode sinnvoller ?

    Ach ja, wenn mit unbenannten Parametern die :2 :2 gemeint ist ? [mytool stringFromNumber:rechnung :2 :2];
    Hier wollte ich einfach die zwei Dezimalstellen einstellen für den Rückabestring, oder muss ich die zuvor
    in Variablen packen ? Wäre ja umständlich.

    Für das Speichern der Eingaben eines Fahrzeuges werde ich dann wohl eine Klasse "Auto" erstellen
    und darin Probertys für die Daten wie z.B. Hersteller, KFZ-Nr, Baujahr usw.
    Ich glaube das wäre richtiger als in Variablen speichern, das habe ich jetzt verstanden.

    Bin ich auf dem richtigen Weg ?
    MfG. Bernhard
    (hb-mobilesoft.de)

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von Paulsche ()

  • Du bist mäßig auf dem richtigen Weg:

    1. gritsch hat bereits gesagt, dass eine Kategorie hierfür das Richtige ist.

    2. Wenn du dort einfach die zwei Dezimalstellen einstellen möchtest, warum nennst du die Methode dann nicht stringFromNumber:minimumFractionDigits:maximumFractionDigits:?

    Zusammen genommen:

    Quellcode

    1. @interface NSNumber(FormatterAddition)
    2. - (NSString*)stringWithMinimumFractionDigits:(NSUInteger)minimumFractionDigits maximumFractionDigits:(NSUInteger)maximumFractionDigits;
    3. @end


    Quellcode

    1. @implementation NSNumber(FormatterAddition)
    2. - (NSString*)stringWithMinimumFractionDigits:(NSUInteger)minimumFractionDigits maximumFractionDigits:(NSUInteger)maximumFractionDigits
    3. {
    4. NSNumberFormatter *formatter = [[NSNumberFormatter alloc] init];
    5. [formatter setLocale:[NSLocale currentLocale]];
    6. formatter.numberStyle = NSNumberFormatterDecimalStyle;
    7. formatter.maximumFractionDigits = maximumFractionDigits;
    8. formatter.minimumFractionDigits = minimumFractionDigits;
    9. NSString *string = [formatter stringFromNumber:self];
    10. return string;
    11. }
    Alles anzeigen


    Für das Protokoll:

    1. Das ist immer noch entfernt von gutem Code. Aber das Schlimmste ist weg.

    2. Es wird dir mutmaßlich bei deinem eigentlichen Problem nicht helfen. Siehe hierzu den Beitrag von Thallius.
    Es hat noch nie etwas gefunzt. To tear down the Wall would be a Werror!
    25.06.2016: [Swift] gehört zu meinen *Favorite Tags* auf SO. In welcher Bedeutung von "favorite"?
  • Ah, ok , das ist mit Parameter ohne Namen gemeint gewesen, aussagekräftige Namen :)
    ok.

    Ich lese mich mal genauer in Klassen und Methoden, Klassenmethoden, Categorien ein
    und werde einfach mal probieren, bevor ich weiter mit Fragen komme, ist schon eine
    Umgewöhnung aus einer Visualbasic ähnlichen Sprache in Objectiv-C umzusteigen,
    aber macht auch Spass, da ich schon merke dass alles strukturierter ist, aber dadurch
    (am Anfang) auch aufwändiger.
    MfG. Bernhard
    (hb-mobilesoft.de)
  • Also, ich habe das jetzt so gelöst,eine Klasse Tools erstellt, darin KlassenMethoden für meine Tools-Funktionen die ich immer wieder im Code benötige.
    Beispiel: KlassenMethode um Eingabe in Textfelder für Dezimalzahlen formatieren.

    Quellcode

    1. + (NSString*)stringWithDecimalNumber :(NSString*)stringWithNumber :(NSUInteger)minimumFractionDigits :(NSUInteger)maximumFractionDigits
    2. {
    3. NSNumberFormatter *formatter = [[NSNumberFormatter alloc] init];
    4. [formatter setLocale:[NSLocale currentLocale]];
    5. formatter.numberStyle = NSNumberFormatterDecimalStyle;
    6. formatter.minimumFractionDigits = minimumFractionDigits;
    7. formatter.maximumFractionDigits = maximumFractionDigits;
    8. double numberFromString = [[formatter numberFromString:stringWithNumber] doubleValue];
    9. NSString *stringFromNumber = [formatter stringFromNumber:[NSNumber numberWithDouble:numberFromString]];
    10. return stringFromNumber;
    11. }
    Alles anzeigen

    Aufruf der Methode:

    Quellcode

    1. _tf02liter.text = [Tools stringWithDecimalNumber :_tf02liter.text :3 :3]; // Textfeld mit formatiertem Dezimalstring


    Ich denke die Lösung ist so ok, mit Kategorie wäre es auch gegangen, aber da müsste ich für jede Tool-Funktion eine Kategorie mit jeweils eigenen .h .m Dateien erstellen.
    Oder liege ich mit meiner Lösung voll daneben ? Bin mir noch unsicher.
    MfG. Bernhard
    (hb-mobilesoft.de)
  • Ich verstehe immer noch nicht, warum du unbedingt die Funktionalität eines NSNumberFormatters in eine Klassenmethode kapseln willst - meiner Meinung nach hast du davon nur den Nachteil, dass du dich fortan händisch mit dem ganzen Zeug herumschlagen musst. Außerdem erzeugst du für jede Formatierung eine NSNumberFormatter-Instanz, lässt sie eine Zahl formatieren und wirfst sie dann weg. Das ist fürchterlich ineffizient.

    Die Formatter haben einen eigenen Zustand, das ist keine Einschränkung, sondern ein Feature (ein tolles!). Sie dürfen (und sollen) wiederverwendet werden. Dazu muss man sie nur an die entsprechenden Textfelder hängen und fertig, der Rest passiert automatisch.
    Multigrad - 360°-Produktfotografie für den Mac
  • Michael schrieb:

    Paulsche schrieb:

    Ich denke die Lösung ist so ok

    Du hast nur wieder unbenannte Parameter.


    Hm, als Parameter brauche ich doch nur die :2 :2 für 2 Dezimalstellen, sollte ich dafür wirklich extra zwei Variablen
    definieren ? Dar man als Parameter keine direkten Werte übergeben ?

    Es müsste also so aussehen das es ok wäre ?

    Quellcode

    1. NSUInteger *minimumFractionDigits = 3;
    2. NSUInteger *maximumFractionDigits = 3;
    3. _tf02liter.text = [Tools stringWithDecimalNumber :_tf02liter.text :minimumFractionDigits :minimumFractionDigits]; // Textfeld mit formatiertem Dezimalstring
    MfG. Bernhard
    (hb-mobilesoft.de)

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von Paulsche ()

  • mattik schrieb:

    Ich verstehe immer noch nicht, warum du unbedingt die Funktionalität eines NSNumberFormatters in eine Klassenmethode kapseln willst - meiner Meinung nach hast du davon nur den Nachteil, dass du dich fortan händisch mit dem ganzen Zeug herumschlagen musst. Außerdem erzeugst du für jede Formatierung eine NSNumberFormatter-Instanz, lässt sie eine Zahl formatieren und wirfst sie dann weg. Das ist fürchterlich ineffizient.

    Die Formatter haben einen eigenen Zustand, das ist keine Einschränkung, sondern ein Feature (ein tolles!). Sie dürfen (und sollen) wiederverwendet werden. Dazu muss man sie nur an die entsprechenden Textfelder hängen und fertig, der Rest passiert automatisch.


    Ok, ich möchte nach jeder Textfeldeingabe den string (Zahl) in ein individuelles Dezimalzahlformat (1,2,3 Kommastellen) formatieren können.
    Das mit der jedesmal instanzierung leuchtet ein daß das nicht sinnvoll ist, ich sollte wohl in jeder Controllerklasse in ViewDidLoad die Initialisierung machen
    und nach Textfeldeingabe die restliche Anpassung für die Dezimalstellen, richtig ?

    Hatte dann wohl einen Denkfehler ?
    MfG. Bernhard
    (hb-mobilesoft.de)
  • Paulsche schrieb:

    Hm, als Parameter brauche ich doch nur die :2 :2 für 2 Dezimalstellen, sollte ich dafür wirklich extra zwei Variablen
    definieren ? Dar man als Parameter keine direkten Werte übergeben ?

    Natürlich darfst du direkt Werte übergeben. Die Parameter werden nicht beim Aufruf benannt, sondern bei der Methodendeklaration.

    Paulsche schrieb:

    Es müsste also so aussehen das es ok wäre ?

    Quellcode

    1. NSUInteger *minimumFractionDigits = 3;
    2. NSUInteger *maximumFractionDigits = 3;
    3. _tf02liter.text = [Tools stringWithDecimalNumber :_tf02liter.text :minimumFractionDigits :minimumFractionDigits]; // Textfeld mit formatiertem Dezimalstring

    Nein, der Selector deiner Methode hier ist stringWithDecimalNumber:::. Wie du siehst, haben die Parameter zwei und drei keinen Namen. Wie die Methode mit benannten Parametern aussehen könnte hat Amin hier schon geschrieben.
  • Ah, ok , vor dem Parameter :parameter noch einen Namen setzen z.B. Parametername:parameter

    Ich glaub jetzt hab ichs kapiert.

    Nur wo ich denn jetzt genau in meiner Controllerklasse den NSNumberFormatter definiere,
    so dass ich in allen Methoden der Controllerklasse den Formatter benutzen kann,
    das habe ich noch nicht hinbekommen.

    In den Beispielen die ich so beim googeln finde, wird der Formatter jedesmal beim benutzen initialisiert.
    MfG. Bernhard
    (hb-mobilesoft.de)
  • Wenn Du den Formatter als Property in Deiner Klasse definierst, dann ist es total egal wo und wann du den Formatter instanzierst.

    Ich glaube Du bist ein wenig zu ungeduldig oder auch ungenau. Programmieren ist nichts was man so hin bastelt. Da muss man sich alles genau durchlesen und verstehen. Mir scheint du überfliegst alles nur und verpasst dabei die Hälfte aller Grundlagen. Fang einfach noch mal von vorne an und mache nicht weiter bevor du alles genau verstanden und umgesetzt hast.

    Gruß

    Claus
    2 Stunden Try & Error erspart 10 Minuten Handbuchlesen.

    Pre-Kaffee-Posts sind mit Vorsicht zu geniessen :)
  • Oh ja, wenn Du von Java/Android auf Objective-C/iOS umsteigen willst, dann solltest Du wirklich wirklich wirklich langsam machen.

    Wie mattik schon schrieb, solltest Du den Formatter an die Textfelder hängen. Im Gegensatz zu Javas Formatter Implementierungen sind dies nämlich keine 'statischen Methoden' (wir bevorzugen hier den Begriff 'Klassenmethoden') sondern Instanzmethoden, für die Du jedes Mal ein Objekt erzeugst und dann wieder wegwirfst. Eine eher schlechte Idee, nicht nur bei Programmiersprachen ohne Garbage Collection. ;)
    «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
  • Marco Feltmann schrieb:

    Oh ja, wenn Du von Java/Android auf Objective-C/iOS umsteigen willst, dann solltest Du wirklich wirklich wirklich langsam machen.

    Zumal viele Konzepte grundverschieden sind; das fängt schon mit den unterschiedlichen Ablaufzyklen von Activitys und Viewcontrollern an.

    Allerdings finde ich diesen Utils-Klassen-Ansatz mit statischen Methoden, den man in vielen Java-Projekten findet, auch da schon sehr ungünstig.
    „Meine Komplikation hatte eine Komplikation.“