【问题标题】:Get a Swift Variable's Actual Name as String以字符串形式获取 Swift 变量的实际名称
【发布时间】:2014-09-23 22:24:21
【问题描述】:

所以我试图在 Swift 中将实际变量名称作为字符串获取,但还没有找到这样做的方法......或者我可能从一个不好的角度看待这个问题和解决方案。

所以这基本上就是我想做的:

var appId: String? = nil

//This is true, since appId is actually the name of the var appId
if( appId.getVarName = "appId"){
    appId = "CommandoFurball"
}

不幸的是,我无法在苹果文档中找到任何与此接近的内容,但:

varobj.self or reflect(var).summary 

但是,这给出了变量本身内部的信息或在这种情况下为字符串的变量类型的信息,我想要变量的实际名称。

【问题讨论】:

  • 您实际上想通过变量名称来实现什么?这不是 JavaScript 或 Python。诸如此类的动态语言会在运行时保留此类信息。在 Swift 中,变量名纯粹是为了方便程序员(以便给内存地址起人名),它们在运行时并不存在于程序中。
  • @Alexander 对 NSPredicates 很有用 :)
  • 答案似乎是一个问题,“我怎样才能从一个类中获取属性和方法名称,元到只知道它们。”但是,我认为最初的问题更像是 bob.dofunction(ted),dofunction 如何找到字符串“bob”和“ted”。我正在编写 TUITest 代码,它会自行生成输出代码,让它知道它的名字会很好。但是,他将其标记为正确答案,所以他一定已经让它起作用了。另外,回答问题的 NSPredicate 的返回值在哪里?
  • 你有没有让它与方法或函数的名称一起使用?我知道如何让它与属性或变量的名称一起使用,但我想获得方法或函数的名称。

标签: swift reflection


【解决方案1】:

这在 Swift 3 中得到官方支持,使用 #keyPath()

https://github.com/apple/swift-evolution/blob/master/proposals/0062-objc-keypaths.md

示例用法如下所示:

NSPredicate(format: "%K == %@", #keyPath(Person.firstName), "Wendy")

Swift 4 中我们有更好的东西:\KeyPath 表示法

https://github.com/apple/swift-evolution/blob/master/proposals/0161-key-paths.md

NSPredicate(format: "%K == %@", \Person.mother.firstName, "Wendy")

// or

let keyPath = \Person.mother.firstName
NSPredicate(format: "%K == %@", keyPath, "Andrew")

速记是一个受欢迎的补充,能够从变量中引用键路径非常强大

【讨论】:

  • 感谢我的英雄!我只想说value(forKeyPath:)setValue(_, forKeyPath) 这两种方法可以通过这个#keyPath() 使用来执行更改。 IMO 这应该是 Swift 3 新接受的答案。
  • 这个例子中的变量名是什么,它是作为字符串发送/给出的?
  • 这似乎要求类型扩展一个NSObject?是否有类似的东西可以用于“纯 Swift”类?
  • 这也只适用于实际的类和结构属性。它不适用于局部变量或局部常量。
  • 我对 Swift 4 有点困惑。生成的keyPath 不是直接的字符串,Objective-C 运行时期望谓词的初始值设定项。例如,如果Person 是一个核心数据生成的 NSManagedObject 子类,那么它就不能这样工作,因为keyPath 不能转换为“Objective-C-like”键,即字符串(或 @ 987654332@)。我错过了什么吗?
【解决方案2】:

根据this answer 的更新,Swift 3 支持 #keyPath

NSPredicate(format: "%K == %@", #keyPath(Person.firstName), "Andrew")

【讨论】:

  • 我会很糟糕...感谢您的提醒。我害怕这一点,因为这门语言太新了。嗯,有什么办法可以做这种映射?
  • 如果您需要属性或变量元数据,您将不得不自己处理。
  • 我是否遗漏了什么,或者这没有给出问题的答案,我认为这个问题是“你如何获得变量的名称?例如,如果我有一个名为 foo 的变量(与它的类型无关),我认为问题是“如何让字符串“foo”将其存储在另一个变量中?举个例子,下面是你在 C# 中的做法:string nameOfFoo = nameof(foo); 现在,nameOfFoo 中存储的值是字符串“foo”
  • @IdoCohen 的答案应该是公认的答案。他使用 Mirror 来访问变量的名称。
  • 它确实回答了这个问题,不是吗? \#keyPath(Person.firstname) 返回字符串“firstName”,它是“Swift 中的实际变量名作为字符串”我把它放到了一个游乐场并得到了预期的结果。
【解决方案3】:

这是我的解决方案

class Test { 
    var name: String = "Ido"
    var lastName: String = "Cohen"
}

let t = Test()
let mirror = Mirror(reflecting: t)

for child in mirror.children {
    print(child.label ?? "")
}

打印将是

name
lastName

【讨论】:

    【解决方案4】:

    这行得通:

    struct s {
        var x:Int = 1
        var y:Int = 2
        var z:Int = 3
    }
    
    var xyz = s()
    
    let m = Mirror(reflecting: xyz)
    
    print(m.description)
    print(m.children.count)
    for p in m.children {
        print(p.label as Any)
    }
    

    【讨论】:

      【解决方案5】:

      我想出了一个快速的解决方案,但不幸的是它不适用于整数、浮点数和双精度数,我相信。

      func propertyNameFor(inout item : AnyObject) -> String{
          let listMemAdd = unsafeAddressOf(item)
          let propertyName =  Mirror(reflecting: self).children.filter { (child: (label: String?, value: Any)) -> Bool in
              if let value = child.value as? AnyObject {
                  return listMemAdd == unsafeAddressOf(value)
              }
              return false
              }.flatMap {
                  return $0.label!
          }.first ?? ""
          
          return propertyName
      }
      
      var mutableObject : AnyObject = object
      let propertyName = MyClass().propertyNameFor(&mutableObject)
      

      它比较对象属性的内存地址并查看是否匹配。 它不适用于 Ints、Floats 和 Doubles 的原因是它们不是 anyobject 类型,尽管您可以将它们作为 anyobject 传递,但当您这样做时,它们会转换为 NSNumbers。因此内存地址发生变化。 they talk about it here.

      对于我的应用程序,它一点也不妨碍我,因为我只需要它用于自定义类。所以也许有人会觉得这很有用。如果有人可以使用其他数据类型进行这项工作,那将非常酷。

      【讨论】:

      • 我总是得到“”空字符串,当我为我的域类变量执行时......你能帮我调试一下吗,因为我对镜像和其他东西没有更深入的了解? @大卫里斯
      • 当你说域类变量是什么意思?如果你不给我一个例子,我帮不了你。
      • 请在下面的项目中找到 ViewController 文件。 github.com/vivinjeganathan/ErrorHandling/tree/Closures-Refactor
      【解决方案6】:

      完成extensions的已接受答案:

      1. 属性必须是@objc
      var appId:字符串? { …… }
      1. 您需要使用#keyPath 语法,扩展尚不支持\ 表示法。
      #keyPath(YourClass.appId)

      【讨论】:

        【解决方案7】:

        最好的解决方案是Here

        来自给定的链接

        import Foundation
        
        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;
            var myClass: AnyClass = self.classForCoder;
            var properties = class_copyPropertyList(myClass, &count);
        
            // iterate each objc_property_t struct
            for var i: UInt32 = 0; i < count; i++ {
                var property = properties[Int(i)];
        
                // retrieve the property name by calling property_getName function
                var cname = property_getName(property);
        
                // covert the c string into a Swift string
                var name = String.fromCString(cname);
                results.append(name!);
            }
        
            // release objc_property_t structs
            free(properties);
        
            return results;
        }
        

        }

        【讨论】:

        • 此解决方案不提供父类中的属性名称。对吗?
        猜你喜欢
        • 2011-09-30
        • 2015-05-27
        • 2014-05-23
        • 2012-11-16
        • 1970-01-01
        • 2010-09-15
        • 2016-07-12
        相关资源
        最近更新 更多