注意:在here上针对目标c发布了类似的问题,但我想在swift中实现它。
我有一个像swift这样声明的类:
import UIKit
class EachDayCell : UITableViewCell
{
@IBOutlet var dateDisplayLabel : UITextField
@IBOutlet var nameDisplayLabel : UITextField
@IBAction func goToPendingItems(sender : AnyObject) {
}
@IBAction func showDateSelectionPicker(sender : AnyObject) {
}
init(style: UITableViewCellStyle, reuseIdentifier: String!)
{
super.init(style: style, reuseIdentifier: reuseIdentifier)
}
}
现在我想在swift中获取一个数组:dateDisplayLabel,nameDisplayLabel。
我怎样才能做到这一点?
答案 0 :(得分:88)
Mirror
这是一个纯粹的Swift解决方案,但有一些限制:
protocol PropertyNames {
func propertyNames() -> [String]
}
extension PropertyNames
{
func propertyNames() -> [String] {
return Mirror(reflecting: self).children.flatMap { $0.label }
}
}
class Person : PropertyNames {
var name = "Sansa Stark"
var awesome = true
}
Person().propertyNames() // ["name", "awesome"]
限制:
不会返回计算属性,即:
var favoriteFood: String { return "Lemon Cake" }
如果self
是一个类的实例(例如,一个结构),则不会报告其超类的属性,即:
class Person : PropertyNames {
var name = "Bruce Wayne"
}
class Superhero : Person {
var hasSuperpowers = true
}
Superhero().propertyNames() // ["hasSuperpowers"] — no "name"
您可以使用superclassMirror()
解决此问题,具体取决于您的行为。
class_copyPropertyList
如果你正在使用Objective-C对象,你可以使用这种方法:
var count = UInt32()
let classToInspect = NSURL.self
let properties : UnsafeMutablePointer <objc_property_t> = class_copyPropertyList(classToInspect, &count)
var propertyNames = [String]()
let intCount = Int(count)
for var i = 0; i < intCount; i++ {
let property : objc_property_t = properties[i]
guard let propertyName = NSString(UTF8String: property_getName(property)) as? String else {
debugPrint("Couldn't unwrap property name for \(property)")
break
}
propertyNames.append(propertyName)
}
free(properties)
print(propertyNames)
如果classToInspect
为NSURL
,则输出到控制台:
["pathComponents", "lastPathComponent", "pathExtension", "URLByDeletingLastPathComponent", "URLByDeletingPathExtension", "URLByStandardizingPath", "URLByResolvingSymlinksInPath", "dataRepresentation", "absoluteString", "relativeString", "baseURL", "absoluteURL", "scheme", "resourceSpecifier", "host", "port", "user", "password", "path", "fragment", "parameterString", "query", "relativePath", "hasDirectoryPath", "fileSystemRepresentation", "fileURL", "standardizedURL", "filePathURL"]
这不适用于游乐场。只需将NSURL
替换为EachDayCell
(或重复使用与扩展名相同的逻辑),它就可以正常工作。
答案 1 :(得分:24)
这是另一个版本。我认为这很简单和纯粹。
Swift 2.0
protocol Reflectable {
func properties()->[String]
}
extension Reflectable
{
func properties()->[String]{
var s = [String]()
for c in Mirror(reflecting: self).children
{
if let name = c.label{
s.append(name)
}
}
return s
}
}
class Test:Reflectable
{
var name99:String = ""
var name3:String = ""
var name2:String = ""
}
Test().properties()
Swift 1.2
class Reflect:NSObject {
func properties()->[String]
{
let m = reflect(self)
var s = [String]()
for i in 0..<m.count
{
let (name,_) = m[i]
if name == "super"{continue}
s.append(name)
}
return s
}
}
class Test:Reflect
{
var name99:String = ""
var name3:String = ""
var name2:String = ""
}
Test().properties()
答案 2 :(得分:3)
我将bolivia's代码转换为Swift 4.此函数接受NSObject并返回对象的键的字典以及该键的类型。
请注意,类型有点难看。对于原始属性,引擎返回一个字母标识符(如bool为B
,int为i
等)但对于Obj-C类型,它返回@"NSString"
之类的内容。看来这对我来说真的只是一个调试功能我不介意。如果您不想弄乱字典,可以取消注释print
行并将其转储到控制台。 String(cString:cAttr)
还包含许多有用的信息,包括属性是否可变,它是引用样式等等。 For more info on this here's Apple's documentation.
func getKeysAndTypes(forObject:Any?) -> Dictionary<String,String> {
var answer:Dictionary<String,String> = [:]
var counts = UInt32();
let properties = class_copyPropertyList(object_getClass(forObject), &counts);
for i in 0..<counts {
let property = properties?.advanced(by: Int(i)).pointee;
let cName = property_getName(property!);
let name = String(cString: cName)
let cAttr = property_getAttributes(property!)!
let attr = String(cString:cAttr).components(separatedBy: ",")[0].replacingOccurrences(of: "T", with: "");
answer[name] = attr;
//print("ID: \(property.unsafelyUnwrapped.debugDescription): Name \(name), Attr: \(attr)")
}
return answer;
}
答案 3 :(得分:0)
Swift 3.1
let contorller = UIActivityViewController(activityItems: [url], applicationActivities: nil)
var count: UInt32 = 0
guard let properties = class_copyPropertyList(object_getClass(contorller), &count) else {
return
}
for index in 0...count {
let property1 = property_getName(properties[Int(index)])
let result1 = String(cString: property1!)
print(result1)
}
答案 4 :(得分:0)
您也可以像这样在 NSObject
上进行扩展:
extension NSObject {
var properties: [Mirror.Child] {
Mirror(reflecting: self).children.compactMap { $0 }
}
var propertyNames: [String] {
properties.compactMap { $0.label }
}
var propertyValues: [Any] {
properties.map { $0.value }
}
}