2015-08-28 11 views
15

Ich bin neu in Swift und kam gerade über diesen in der Dokumentation:Warum haben Enums in Swift Eigenschaften, aber keine gespeicherten Eigenschaften berechnet?

Berechnete Eigenschaften von Klassen zur Verfügung gestellt, Strukturen und Aufzählungen. Gespeicherte Eigenschaften werden nur von Klassen und Strukturen bereitgestellt.

Warum ist das? Funktionieren verknüpfte Werte für enum wie gespeicherte Eigenschaften? Es scheint, als hätten sie anfängliche Eigenschaften gespeichert - Why no stored type properties for classes in swift?

Antwort

6

enum s Typ Eigenschaften gespeichert haben haben - das heißt, static Eigenschaften. Sie haben keine Instanz Eigenschaften gespeichert. Ich weiß nicht, ob es einen technischen Grund gibt, warum gespeicherte Instanzeigenschaften für enum s nicht verfügbar sind. Sie müssen möglicherweise Ihre Frage im Dev-Forum stellen, wenn Sie eine technische Antwort für "warum" wollen.

In Ihrer Frage fragen Sie, ob die verknüpften Werte wie gespeicherte Eigenschaften funktionieren. Tatsächlich tun sie das und sind flexibler (in mancher Hinsicht) als gespeicherte Eigenschaften für struct s und class es. Jeder case in einem enum kann seinen eigenen spezialisierten Datensatz haben, der damit verbunden ist. Anstatt eine Gruppe von gespeicherten Eigenschaften zu haben, die für alle cases gelten, können Sie die gespeicherten Eigenschaften für jede case individualisieren.

0

Eine Enumeration wird als ein strukturierter Datentyp betrachtet, der geändert werden kann, ohne dass ein String oder Int mehrfach in Ihrem Code geändert werden muss Sorgen Sie sich, das Gleiche mehr als einmal zu ändern. Zum Beispiel Drop-Down-Menü:

Mit gespeicherten Eigenschaften können Sie benötigte Informationen vorberechnen und Code in Ihrer Hauptfunktion reduzieren. Bestes Beispiel ist die Berechnung Größe rect zum Beispiel:

struct Point { 
    var x = 0.0, y = 0.0 
} 
struct Size { 
    var width = 0.0, height = 0.0 
} 
struct Rect { 
    var origin = Point() 
    var size = Size() 
    var center: Point { 
     get { 
      let centerX = origin.x + (size.width/2) 
      let centerY = origin.y + (size.height/2) 
      return Point(x: centerX, y: centerY) 
     } 
     set(newCenter) { 
      origin.x = newCenter.x - (size.width/2) 
      origin.y = newCenter.y - (size.height/2) 
     } 
    } 
} 

var square = Rect(origin: Point(x: 0.0, y: 0.0), 
    size: Size(width: 10.0, height: 10.0)) 
+2

Aber Aufzählungen hatte gespeicherte Eigenschaften zunächst - http: // stackoverflow.com/questions/24029581/why-no-stored-type-properties-for-classes-in-swift –

+0

Nun enum ist struct standardmäßig so vielleicht du kannst es erweitern und machen eine funktion, die das tun kann, aber ich sehe nicht Ein Grund dafür ... sie werden für statische, bekannte, berechnete Strukturen verwendet und der beste Weg sie zu benutzen ist so ... –

2

Ich verwende einen kleinen Trick, um Eigenschaften zu speichern, die bei der Initialisierung nicht zugänglich sind.

Zunächst erstelle ich eine Klasse Future, die die gespeicherte Eigenschaft in Zukunft gespeichert werden:

class Future<T> { 
    var value: T? 
    init(value: T? = nil) { 
     self.value = value 
    } 
} 

Dann erstelle ich meine Enum:

enum Sample { 
    case Test(future: Future<String>) 
} 

Instantiate:

let enumTest = Sample.Test(future: Future()) 

Später im Code:

switch enumTest { 
    case let .Test(future): 
    future.value = "Foo" 
} 

Und später, können Sie den Wert zugreifen:

switch enumTest { 
    case let .Test(future): 
    // it will print Optional("Foo") 
    print("\(future.value)") 
} 

Dies ist nicht etwas, sollten Sie missbrauchen, aber es kann in einigen Fällen hilfreich sein.

Ich hoffe, es hilft.

+0

Warum speichern wir nicht einfach die Zeichenkette oder was auch immer direkt in dem Enum-assoziierten Wert? –

6

Enums, die gespeicherte Instanzeigenschaften nicht zulassen, sind eine Entwurfsauswahl. Wenn Enumeration mit gespeicherten Instanzeigenschaften verwendet wird, wird es wie eine Struktur (mit enum superpowers), aber nur vom Typ Perspektive werden Enums nun wie Typmultiplizierer. Grundsätzlich betrachten

enum Set1 { 
    case a 
    case b 
    case c 
} 

enum Times { 
    case x 
    case y 

    var k: Set1 
} 

Was bedeutet eigentlich, dass Enum Times erlaubt uns, jede Kombination von Elementen aus Set1 und Set2 mit in 6 verschiedene Fälle führt, aber warten wir eigentlich wissen, dies ist ein Ziel eines Tupels Typ wie (Set1, Set2), wo Times als

typealias Times = (Set1, Set2) 

erklärt werden, hoffe ich, dies als eine vernünftige Begründung dient nicht dem ersteren Fall erlaubt.

aber sagte, dass rasche Aufzählungen ermöglichen es uns, mit jedem Fall ein beliebiges n-Tupel Assoziieren, so dass uns zu erklären, was als diskriminierte Union in der funktionalen Programmierung bekannt ist. Nennen Sie es eine gespeicherte Eigenschaft, die an Fall angehängt wird, wenn Sie mögen. Aus Typensicht wirkt es jetzt als Typaddierer.

enum Add { 
    case lhs(Set1) 
    case rhs(Set2) 
} 

Wir haben jetzt 5 verschiedene Fälle. Wenn wir jetzt speichern 2-Tupel:

enum AddTimes { 
    case lhs(Set1, Set2) 
    case rhs(Set3, Set4) 
} 

wir jetzt haben grundsätzlich Summe der Multiplikation (Set1 * Set2 + Set3 * Set4). Dies ist ein sehr leistungsfähiges Werkzeug, wenn es um Mustererkennung geht.

aber gibt es einige echte Fälle, wenn Sie tatsächlich die Form der gespeicherten Eigenschaft in enum emulieren wollen. Bedenken Sie:

public enum Service { 
    case registerNewUser(username: String, password: String, language: String) 
    case login(username: String, password: String, deviceTokenº: String?) 
    case logout(sessionToken: String) 
    case sendForgotPassword(email: String) 
} 

ist eine deklarative Weise REST-Endpunkte definieren (in Rahmen wie Moya) Wenn Sie eine Anforderung feuern wollen Sie so etwas wie

MoyaProvider<Service>.request(.sendForgotPassword(email: "[email protected]")) 

tun würde, aber jetzt stellen Sie sich möchte zwischen Ihrer Produktion und dem Testserver unterscheiden. Wenn Sie einen Server als ein anderes Tupelelement jeweils hinzufügen:

case forgotPassword(sessionToken: String, serverBaseURLString: String) 

dies wird sein, eine falsche Semantik, da man ursprünglich jedes Tupel beabsichtigen Anforderungsparameter zu speichern, aber jetzt speichert es eine Server-Basisadresse.

Um solche Dinge zu vermeiden, können wir unseren Typ folgendermaßen parametrisieren. Stattdessen Server von, wie definiert wird sagen:

enum Server: String { 
    case production = "https://service.info" 
    case test = "http://test.service.info" 
} 

wir es mit bestimmten Typ für jeden Fall wie definieren:

public struct ProductionServer: ServerType { 
    public static var baseURLString: String { return "https://service.info" } 
} 
public struct TestServer: ServerType { 
    public static var baseURLString: String { return "http://test.service.info" } 
} 
public protocol ServerType { 
    static var baseURLString: String { get } 
} 

und schließlich unsere Servicetype parametrisieren als

public enum Service<T> where T: ServerType { 
    case registerNewUser(username: String, password: String, language: String) 
    case login(username: String, password: String, deviceTokenº: String?) 
    case logout(sessionToken: String) 
    case sendForgotPassword(email: String) 

    var serverURL: URL { 
     return T.baseURL 
    } 
} 

public typealias ProdutionService = Service<ProductionServer> 
public typealias TestService = Service<TestServer>