2016-08-11 1 views
2

Ich bin neu zu schnell und ich verstehe nicht wirklich, wie man optionale Wert richtig verwendet.Verwirrt über optionalen Wert in Swift

Die Situation ist: Erstens habe ich eine Modellklasse, um einige Werte seiner Eigenschaften zu speichern und die Anfrage an den Server zu senden, um Werte zu erhalten. Code:

import Foundation 

class User: NSObject { 

    var name: String? 

    func getInfo(updateUI:() ->()) { 
     let manager = AFHTTPSessionManager() 
     manager.POST(URLString, parameters: nil, success: { (task: NSURLSessionDataTask, responseObject: AnyObject?) in 

      let dic = responseObject as? NSDictionary 
      self.name = dic?.objectForKey("name") 
      updateUI() 

     }, failure: { (task: NSURLSessionDataTask?, error: NSError) in 
      log.obj(error) 
    }) 

} 

Zweitens möchte ich in einem Viewcontroller, dieses Modell verwenden, um Werte von Server und Update UI zu erhalten. Code:

class UserViewController: UIViewController { 

    @IBOutlet var nameLabel: UILabel! 
    var user = User() 

    override func viewDidLoad() { 
     super.viewDidLoad() 

     user.getInfo({ 
      nameLabel.text = user.name! 
     }) 
    } 

} 

Ich denke, es ist ein gefährlicher Weg, um diese Arbeit zu handhaben, weil es nichts gibt, kann sicherstellen, dass ich einen bestimmten Namen haben, wenn ich es auf dem Etikett setzen wollen. Es funktioniert in den meisten Fällen ziemlich gut, aber es kann abstürzen, wenn es nicht möglich ist, einen richtigen Wert vom Server zu erhalten (zum Beispiel gibt es keinen Wert für den Schlüssel "name").

Ich habe zwei Ideen, Fragen über:

  1. einen Standardwert Geben Sie für die Eigenschaften wie: var name = ""
  2. Testen Sie den Wert vor der Verzerrung rückgängig es mag:

    if let foo = user.name { 
        nameLabel.text = foo 
    } 
    

Ich möchte den ersten Weg wählen, weil:

  1. Ich denke, das Anzeigen einer Standardzeichenfolge auf dem Label ist viel akzeptabler als ein Absturz, weil ein optionaler Wert nicht aufgehoben werden kann.
  2. Wenn ich viel mehr Werte zu verwenden habe, wird der Code sehr lang und schwierig zu lesen sein.

Wählte ich einen richtigen? Oder beide verstanden die Verwendung von optionalem Wert nicht und es gibt einen besseren Weg? Jemand kann mir helfen?

+0

Eine Sache, die ich sofort aus der Box denken kann, ist, dass Sie Speicher auf Variablen zuweisen, die mit Nullwerten enden könnten. Daher weisen Sie mehr Speicher zu als Sie jemals benötigen. (Diese Zuordnung ist vielleicht unbedeutend, aber eine Tatsache, die berücksichtigt werden muss) – Harsh

+2

Sie möchten nicht den Standardwertansatz ('var name =" "') verwenden. Die optionale Bindung ('if name = user.name {nameLabel.text = name}') zu _unwrap_ optional ist definitiv der richtige Weg. Oder benutze den 'nil' Colaescing-Operator' '', wie dir pbrush25 gezeigt hat. Aber die Frage "Was soll ich zeigen, wenn es keinen Namen gibt" ist eine Benutzeroberflächenfrage (erledigt beim Setzen des "Textes" des Etiketts), nicht etwas, das man generell in das Modell einbauen möchte. Ein "nil" -Option im Modell zu haben, wenn keine Daten vorhanden sind, ist der richtige Ansatz. – Rob

Antwort

3

Sie können sicher einen optionalen oder geben Sie es einen Standardwert, ohne eine neue Variable zu deklarieren wie so auspacken:

nameLabel.text = user.name ?? "" 

Dies ist die nil Koaleszierstruktur Operator aufgerufen und wird versuchen, eine optionale auszupacken, und wenn der unwrap ist nicht erfolgreich, wird es den Standardwert geben, den Sie auf der rechten Seite des Operators platziert haben.

3

Ihre Instinkte sind korrekt, dass die Kraftentfaltung optional ist nicht ratsam. Sie sind auch richtig, dass die Angabe eines Nicht-Null-Default-Werts den Zweck eines Optional nicht erfüllt.

if let foo = user.name Bindung ist eine solide Art und Weise, dies zu tun, aber wenn alles, was Sie tun, um einen Wert zuweisen, können Sie sich die geschweiften Klammern ersparen, indem die Null Koaleszenz-Operator, wie pbush25 heißt es:

nameLabel.text = user.name ?? "Default Label Text"

Dies bedeutet "packen Sie user.name aus und wenn der Wert nicht null ist, verwenden Sie ihn. Anderenfalls verwenden Sie den folgenden Wert:" Sie können sie sogar zusammenketten, wenn Sie beispielsweise die Benutzerkennung als Fallback-Label verwenden möchten Text, aber die ID könnte auch nicht existieren:

nameLabel.text = user.name ?? user.id ?? "No name or ID".

Auch wenn Sie in dem Fall zum Absturz bringen wollen, dass der optionale Wert Null ist, wäre es besser zu assert oder benutzt ein preconditionFailure() als einfach die optionale zu zwingen auspacken, so dass Sie zumindest eine Fehlermeldung zur Verfügung stellen können.