2016-07-09 3 views
-1

Ich habe eine Struktur und ich würde gerne wissen, ob ich Variablen mit Klammer-Syntax zugreifen kann. Hier ist meine Struktur:Kann man in Swift eine Zeichenfolge verwenden, um auf eine Struktureigenschaft zuzugreifen?

import UIKit 

public struct Pixel { 
    public var value: UInt32 
    public var red: UInt8 
    public var green: UInt8 
    public var blue: UInt8 
    public var alpha: UInt8 
} 

public struct RGBAImage { 
    public var pixels: [ImageProcessor_Sources.Pixel] 
    public var width: Int 
    public var height: Int 
    public init?(image: UIImage) 
    public func toUIImage() -> UIImage? 
} 

Ich mag die Variable zugreifen wie so pixel["red"], im Gegensatz zu pixel.red

var image = RGBAImage(image: image!)! 
var pixel = image.pixels[index] 
pixel["red"] = 255 // as opposed to pixel.red 

Gibt es eine Möglichkeit, dies in Swift zu tun?

+0

Nein, können Sie nicht (es sei denn, Sie erstellen ein Wörterbuch für die Komponenten oder eine benutzerdefinierte Abonnementlogik). Was ist der Vorteil des Zeichenketten-Abonnements? Literale Strings sind immer fehleranfällig. – vadian

+0

was passiert im Falle von Pixel ["aosiubd"] '? – luk2302

+0

Nun, ich versuche die Dinge trocken zu halten. Ich stimme zu, dass die Dinge fehleranfälliger sein werden, aber ich würde gerne in der Lage sein, einen String in eine Funktion zu übergeben und diese als Lookup zu verwenden, ähnlich einem Python-Wörterbuchschlüssel. Ich muss nun dieses Stück Code für die ROTEN, GRÜNEN und BLAUEN Kanäle schreiben: 'pixel.red = UInt8 (max (0, min (255, rgbArray [0] + diff * intensity))) ' –

Antwort

3

Ich glaube nicht, String-basierten Zugriff wie dies ist gut Swift Stil. vadian shows wie es getan werden kann, aber dynamisch zu erhalten und die Mitglieder wie folgt gesetzt werden, wäre es am besten the built-in keypath functionality zu verwenden:

let redChannel = pixel[keyPath: \.red] 
pixel[keyPath: \.green] = 0xB5 

Eine weitere Option (relevantere vor Swift 4) wäre eine ENUM zu nutzen zu definieren die Tasten:

enum Component 
{ 
    case red 
    case green 
    case blue 
    case alpha 
} 

Dann passen die subscript Funktion, die demonstriert Vadian Pixel.Component statt String zu akzeptieren.

Dies hat den entscheidenden Vorteil, dass Sie keinen ungültigen Schlüssel mehr weitergeben können.

Basierend auf Ihrer Definition:

public extension Pixel 
{ 
    public enum Component 
    { 
     case red, blue, green, alpha 
    } 

    public subscript(key: Component) -> UInt8 
    { 
     get 
     { 
      switch key { 
       case .red: return self.red 
       case .green: return self.green 
       case .blue: return self.blue 
       case .alpha: return self.alpha 
      } 
     } 
     set 
     { 
      switch key { 
       case .red: self.red = newValue 
       case .green: self.green = newValue 
       case .blue: self.blue = newValue 
       case .alpha: self.alpha = newValue 
      } 
     } 
    } 
} 

var pxl = Pixel(value: 0xFEEDFACE, red: 0xFE, green: 0xED, blue: 0xFA, alpha: 0xCE) 
let redChannel = pxl[.red] 
print(redChannel) 
pxl[.green] = 0xB5 
print(pxl) 
+0

Dank @Josh, wenn Sie demonstrieren, Subskript hinzufügen PixelComponent anstelle von String akzeptieren würde ich dies als die richtige Antwort markieren. –

+0

Es ist eine einfache Umstellung von vadian's Code; Ich habe es der Vollständigkeit halber hinzugefügt. –

+0

ausgezeichnet, Prost. –

1

Just for fun und um zu zeigen, dass es möglich ist, aber es ist hässlich

public struct Pixel { 
    public var value: UInt32 
    public var red: UInt8 
    public var green: UInt8 
    public var blue: UInt8 
    public var alpha: UInt8 

    subscript(key: String) -> UInt8 { 
    get { 
     switch key { 
     case "red": return self.red 
     case "green": return self.green 
     case "blue": return self.blue 
     case "alpha": return self.alpha 
     default: fatalError("Invalid key") 
     } 
    } 
    set { 
     switch key { 
     case "red": self.red = newValue 
     case "green": self.green = newValue 
     case "blue": self.blue = newValue 
     case "alpha": self.alpha = newValue 
     default: fatalError("Invalid key") 
     } 
    } 
    } 
} 
2

Was Sie beschreiben nicht ein Swift-Funktion ist, es sei denn, Sie Subskribierung verwenden (wie Vadian erklärt hat). Wenn Sie möchten, dass Subskriptionen automatisch bereitgestellt werden, verwenden Sie ein Wörterbuch. Andernfalls, wenn Sie echte Introspektion wirklich wollen, verwenden Sie Cocoa - verwenden Sie eine von NSObject abgeleitete Klasse anstelle einer Struktur und verwenden Sie Schlüsselwert-Codierung.

Verwandte Themen