2014-12-07 17 views
8

C'è un modo per mappare un valore non letterale come la tupla del dizionario in enumerazione? Il seguente codice genererà Raw value for enum must be literal.enum di valori non letterali in Swift

enum FileType { 
    case VIDEO = ["name": "Video", "contentTypeMatcher": "video/"] 
    case IMAGE = ["name": "Image", "contentTypeMatcher": "image/"] 
    case AUDIO = ["name": "Audio", "contentTypeMatcher": "aduio/"] 
    case PDF = ["name": "PDF", "contentTypeMatcher":"application/pdf"] 
    case TEXT = ["name": "Text", "contentTypeMatcher": "text/"] 
    case FOLDER= ["name": "Folder", "contentTypeMatcher" :"application/x-directory"] 
    case PLAIN = ["name": "Plain", "contentTypeMatcher": ""] 
} 

E 'lo stesso quando uso tuple:

enum FileType { 
    case VIDEO = (name: "Video", contentTypeMatcher: "video/") 
    case IMAGE = (name: "Image", contentTypeMatcher: "image/") 
    case AUDIO = (name: "Audio", contentTypeMatcher: "aduio/") 
    case PDF = (name: "PDF", contentTypeMatcher:"application/pdf") 
    case TEXT = (name: "Text", contentTypeMatcher: "text/") 
    case FOLDER = (name: "Folder", contentTypeMatcher :"application/x-directory") 
    case PLAIN = (name: "Plain", contentTypeMatcher: "") 
} 
+0

I valori grezzi per enumerazione devono essere o essere convertibili in numeri interi, numeri in virgola mobile, stringhe o singoli caratteri. – i40west

risposta

4

La guida al linguaggio, quando si parla di Enumeration Declaration, afferma chiaramente che:

il tipo grezzo valore deve essere conforme al Protocollo equabile e uno dei seguenti protocolli convertibili letterali: IntegerLiteralConvertible per letterali interi, FloatingPointLiteralConvertible per letterali a virgola mobile, StringLiteralConvertible per stringhe letterali t hat contiene un numero qualsiasi di caratteri e ExtendedGraphemeClusterLiteralConvertible per stringhe letterali che contengono solo un singolo carattere.

Quindi nient'altro che letterali possono essere utilizzati come valori non elaborati.

Una possibile soluzione è quella di rappresentare il dizionario come una stringa - per esempio, è possibile separare gli elementi con virgole, e la chiave di valore con i due punti:

enum FileType : String { 
    case VIDEO = "name:Video,contentTypeMatcher:video/" 
    case IMAGE = "name:Image,contentTypeMatcher:image/" 
    ... 
} 

Poi, utilizzando una proprietà computerizzata (o di un metodo se si preferisce), ricostruire il dizionario:

var dictValue: [String : String] { 
    var dict = [String : String]() 

    var elements = self.rawValue.componentsSeparatedByString(",") 
    for element in elements { 
     var parts = element.componentsSeparatedByString(":") 
     if parts.count == 2 { 
      dict[parts[0]] = parts[1] 
     } 
    } 

    return dict 
} 
4

@Antonio offre una soluzione alternativa ma non risponde alla domanda effettiva.

Definisci il tuo enum.

enum FileType { 

    case Image, Video 
} 

Dare casi, i valori non letterali, qualunque sia il tipo che desiderate con conforme alla RawRepresentable protocollo. Fallo per estensione enum per avere un codice più pulito.

extension FileType: RawRepresentable { 

    typealias Tuple = (name: String, contentTypeMatcher: String) 

    private static let allCases = [FileType.Image, .Video] 

    // MARK: RawRepresentable 

    typealias RawValue = Tuple 

    init?(rawValue: Tuple) { 

     guard let c = {() -> FileType? in 

      for iCase in FileType.allCases { 
       if rawValue == iCase.rawValue { 
        return iCase 
       } 
      } 
      return nil 

     }() else { return nil } 
     self = c 
    } 

    var rawValue: Tuple { 

     switch self { 
     case .Image: return Tuple("Image", "image/") 
     case .Video: return Tuple("Video", "video/") 
     } 
    } 
} 

Per poter abbinare Tuple interruttore, implementare modello operatore di corrispondenza.

private func ~= (lhs: FileType.Tuple, rhs: FileType.Tuple) -> Bool { 

    return lhs.contentTypeMatcher == rhs.contentTypeMatcher && lhs.name == rhs.name 
} 

E questo è tutto ...

let a = FileType.Image 
print(a.rawValue.name) // "Image" 
let b = FileType(rawValue: a.rawValue)! 
print(a == b) // "true" 
print(b.rawValue.contentTypeMatcher) // "image/" 

Diciamo che ho risposto alla domanda senza mettere in discussione. Ora ... Enums (almeno in Swift) sono progettati per avere casi unici. L'avvertimento è che puoi (spero per caso) di tenere lo stesso rawValue per più casi. Generalmente il tuo codice di esempio mi odora. A meno che tu (per ragioni molto ragionevoli) non sia necessario creare un nuovo valore enum dalla tupla, prendi in considerazione la riprogettazione. Se vuoi andare con questa soluzione alternativa, suggerisco (dipende dal progetto) di implementare alcuni controlli se tutti i valori grezzi di tutti i casi sono unici. In caso contrario, prendere in considerazione:

enum FileType { 

    case Video, Image 

    var name: String { 
     switch self { 
     case .Image: return "Image" 
     case .Video: return "Video" 
    } 

    var contentTypeMatcher: String { 
     switch self { 
     case .Image: return "image/" 
     case .Video: return "video/" 
    } 
}