In Swift, can one use a string to access a struct property?

后端 未结 4 779
粉色の甜心
粉色の甜心 2021-01-24 15:53

I have a struct and I would like to know if I can access variables using bracket syntax. Here is my struct:

import UIKit

public struct Pixel {
    public var v         


        
相关标签:
4条回答
  • 2021-01-24 15:59

    I don't think string-based access like this is good Swift style. vadian shows how it can be done, but to dynamically get and set members like this, it would be best to use the built-in keypath functionality:

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

    Another option (more relevant prior to Swift 4) would be to use an enum to define the keys:

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

    Then adapt the subscript function that vadian demonstrated to accept Pixel.Component instead of String.

    This has a significant advantage in that you can no longer pass an invalid key.

    Based on your 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 讨论(0)
  • 2021-01-24 16:02

    Just for fun and to show that it is possible, but it's ugly

    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")
          }
        }
      }
    }
    
    0 讨论(0)
  • 2021-01-24 16:07

    What you're describing is not a Swift feature, unless you use subscripting (as vadian has explained). If you want something that supplies subscripting automatically, use a dictionary. Otherwise, if you really want true introspection, use Cocoa — use a class derived from NSObject instead of a struct, and employ key-value coding.

    0 讨论(0)
  • 2021-01-24 16:15

    If OP is looking for a cleaner alternative, there is a pod that extends KVC to native Swift structs:

    https://github.com/bradhilton/SwiftKVC

    0 讨论(0)
提交回复
热议问题