J'ai un objet qui stocke des URL s. Dans l'exemple ci-dessous, l'objet n'a que 4 propriétés, mais dans mon cas, il y en a plus, donc je veux savoir s'il existe un moyen de le faire avec plus d'élégance.


public final class MyObject: NSObject {

  private let firstURL: URL
  private let secondURL: URL
  private let thirdURL: URL
  private let fourthURL: URL

  public func values() -> [URL] {
    return // <--- I need to return URLs from properties like [firstURL, secondURL, thirdURL, fourthURL]
  }
}

J'ai trouvé une extension de NSObject pour renvoyer un tableau du nom des propriétés sous forme de String.

Source d'extension


public extension NSObject {

  //
  // Retrieves an array of property names found on the current object
  // using Objective-C runtime functions for introspection:
  // https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/ObjCRuntimeGuide/Articles/ocrtPropertyIntrospection.html
  //
  func propertyNames() -> Array<String> {
    var results: Array<String> = []

    // retrieve the properties via the class_copyPropertyList function
    var count: UInt32 = 0
    let myClass: AnyClass = classForCoder
    let properties = class_copyPropertyList(myClass, &count)

    // iterate each objc_property_t struct
    for i in 0..<count {
      if let property = properties?[Int(i)] {
        // retrieve the property name by calling property_getName function
        let cname = property_getName(property)

        // covert the c string into a Swift string
        results.append(cname.debugDescription)
      }
    }

    // release objc_property_t structs
    free(properties)

    return results
  }
}

Mais il retourne un tableau des noms de propriétés comme ["firstURL", "secondURL", "thirdURL", "fourthURL"]. Je veux renvoyer des valeurs au lieu de noms.

2
emrcftci 1 juin 2020 à 12:39

3 réponses

Meilleure réponse

Vous pouvez utiliser Mirror

public final class MyObject: NSObject {
  private let firstURL: URL
  private let secondURL: URL
  private let thirdURL: URL
  private let fourthURL: URL

  public init(firstURL: URL, secondURL: URL, thirdURL: URL, fourthURL: URL) {
    self.firstURL = firstURL
    self.secondURL = secondURL
    self.thirdURL = thirdURL
    self.fourthURL = fourthURL
  }

  public func values() -> [URL] {
    return Mirror(reflecting: self).children.compactMap({ $0.value as? URL })
  }
}

let url = URL(string: "https://stackoverflow.com/")!
let myObject = MyObject(firstURL: url, secondURL: url, thirdURL: url, fourthURL: url)
print(myObject.values()
// [https://stackoverflow.com/, https://stackoverflow.com/, https://stackoverflow.com/, https://stackoverflow.com/]
1
Vicaren 1 juin 2020 à 09:56

Vous pouvez utiliser Mirror et parcourir tout children:

struct Foo {
    let a: String
    let b: String
    let x: Int

    func propsAsArray() -> [Any] {
        let mirror = Mirror(reflecting: self)
        return mirror.children.map { $0.value }
    }
}


let f = Foo(a: "foo", b: "bar", x: 42)
print(f.propsAsArray()) // ["foo", "bar", 42]
1
Gereon 1 juin 2020 à 09:53

Vous pouvez utiliser Mirror, puis mapper les valeurs à l'URL à l'aide de compactMap (pour exclure toute propriété non URL)

public func values() -> [URL] {
    let mirror = Mirror(reflecting: self)

    return mirror.children.compactMap { $0.value as? URL}
}
0
Joakim Danielson 1 juin 2020 à 09:54