Swift Mirror reflection not returning properties o

2019-04-27 23:18发布

问题:

Trying to get all properties of UIView or UIViewController with the follownig:

func propertysNames()->[String]{
    var s = [String]()
    for c in Mirror(reflecting: self).children
    {
        if let name = c.label{
            s.append(name)
        }
    }
    return s
}

This works on UIVIewController, but UIView does not seem to return properties, any advice?

回答1:

Not sure what you are trying to achieve but UIView inherits NSObject. Because of this, you have much of the objc runtime at your disposal. So as an alternative, you could do the following:

import UIKit

extension NSObject {
  func propertysNames() -> [String]{
    var count : UInt32 = 0
    let classToInspect = self.dynamicType
    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]
      let propertyName = NSString(UTF8String: property_getName(property))!
      propertyNames.append(propertyName as String)
    }
    free(properties)
    return propertyNames
  }
}

print(UIView().propertysNames())
// prints: "["_mayRemainFocused", "_sensitivitySize", "skipsSubviewEnumeration", "viewTraversalMark", "viewDelegate", "monitorsSubtree", "backgroundColorSystemColorName", "currentScreenScale", "maskView", "_userInterfaceIdiom", "hash", "superclass", "description", "debugDescription", "gesturesEnabled", "deliversTouchesForGesturesToSuperview", "deliversButtonsForGesturesToSuperview", "_shouldReverseLayoutDirection", "leadingAnchor", "trailingAnchor", "leftAnchor", "rightAnchor", "topAnchor", "bottomAnchor", "widthAnchor", "heightAnchor", "centerXAnchor", "centerYAnchor", "firstBaselineAnchor", "lastBaselineAnchor", "_keyboardOrientation", "_touchForceObservable", "_inheritedRenderConfig", "_lightStyleRenderConfig", "_accessoryViewFrame", "unsatisfiableConstraintsLoggingSuspended", "hash", "superclass", "description", "debugDescription", "hash", "superclass", "description", "debugDescription", "userInteractionEnabled", "tag", "layer", "focused", "semanticContentAttribute", "interactionTintColor", "_layoutDebuggingIdentifier", "_countOfMotionEffectsInSubtree", "_maskView", "_ancestorDefinesTintColor", "_ancestorDefinesTintAdjustmentMode", "_presentationControllerToNotifyOnLayoutSubviews", "_rawLayoutMargins", "_inferredLayoutMargins", "_dontUpdateInferredLayoutMargins", "_tracksFocusedAncestors", "_countOfFocusedAncestorTrackingViewsInSubtree", "_mutableLayoutGuides", "_mutableLayoutArrangements", "_hiddenManagedByLayoutArrangementCount", "_pendingHiddenCount", "previewingSegueTemplateStorage", "_continuousCornerRadius", "_canBeParentTraitEnviroment", "_layoutEngine", "_boundsWidthVariable", "_boundsHeightVariable", "_minXVariable", "_minYVariable", "_internalConstraints", "_constraintsExceptingSubviewAutoresizingConstraints", "unsatisfiableConstraintsLoggingSuspended", "_shouldArchiveUIAppearanceTags", "_interactionTintColor", "_backdropMaskViewForGrayscaleTint", "_backdropMaskViewForColorTint", "_backdropMaskViewForFilters", "_backdropMaskViews", "_wantsGeometryChangeNotification", "contentSizeNotificationToken", "layoutMarginsGuide", "readableContentGuide", "hash", "superclass", "description", "debugDescription", "traitCollection", "preferredFocusedView", "center", "bounds", "transform", "collisionBoundsType", "collisionBoundingPath"]\n"

Also, I do see some weirdness applying your code to UIKit objects. Not sure what the variable is that causes it to fail. It seems to work fine on NSObject types written in Swift:

import UIKit

class Fruit {
  var type=1
  var name="Apple"
  var delicious=true
}

var s = [String]()
for c in Mirror(reflecting: Fruit()).children
{
  if let name = c.label{
    s.append(name)
  }
}

print(s)
// works: "["type", "name", "delicious"]\n"

class FruitNSObject: NSObject {
  var type:NSNumber=1
  var name:NSString="Apple"
  var delicious=true
}

s = [String]()
for c in Mirror(reflecting: FruitNSObject()).children
{
  if let name = c.label {
    s.append(name)
  }
}

print(s)
// works: "["type", "name", "delicious"]\n"

s = [String]()
for c in Mirror(reflecting: UIView()).children
{
  if let name = c.label {
    s.append(name)
  }
}

print(s)
// doesn't work: "[]\n"

s = [String]()
for c in Mirror(reflecting: UIViewController()).children
{
  if let name = c.label {
    s.append(name)
  }
}

print(s)
// doesn't work: "[]\n"

So either this is a bug or there is some limitation in the Swift <-> ObjC in the current version of Swift. Perhaps it has to do with what @user3441734 pointed out in his answer.

BTW, all code was run on the most current version of Xcode (that's 7.1.1) in a playground.



回答2:

import UIKit

let viewController = UIViewController()
let view = UIView()
class MyViewController: UIViewController {
    let i = 1
    let myView = MyView()
}
class MyView : UIView {
    let label = UILabel()
    let i = 1
}

Mirror(reflecting: MyViewController()).children.count   // 2
Mirror(reflecting: MyView()).children.count             // 0

You are right! Just fill the bug report ...

or it is sabotage, because i found this

extension UIView : _Reflectable {
}