¿Puedes labelr vistas en la salida de la console de AutoLayout sin usar Storyboards?

Estoy viendo las charlas de WWDC en AutoLayout, y he aprendido que tener configurado StoryboardID en tus vistas hace que la salida de la console para los conflictos de restricciones sea mucho más fácil de leer (es decir, obtienes un nombre en lugar de solo una dirección). Te muestran dónde configurar StoryboardID (anteriormente solo "Identificador") en Interface Builder, pero ¿hay alguna manera de hacerlo en código? Estoy intentando depurar un set grande y complicado de vistas que no escribí yo mismo, en una aplicación que es 100% programática, que tiene muchas limitaciones insatisfactorias, y que (de alguna manera) funcionaba en iOS 7 pero comenzó a romperse en iOS 8. Me encantaría tener una <UIView:0x8675309> clara de qué <UIView:0x8675309> realmente está causando el problema.

Miré por encima de la reference de la class UIView, no se encontró ningún "Identificador" o "StoryboardID".

No estaría demasiado sorprendido si la respuesta es "no". Después de todo, se llama una ID de Storyboard por una razón. Pero agradecería una confirmación y una solución para que el volcado de la console de AutoLayout sea más legible si es posible.

Me encantaría tener una idea clara de lo que realmente está causando el problema.

Tengo dos sugerencias.

  1. En Xcode, durante la misma ejecución de la aplicación (preferiblemente, justo después de que se obtiene, se obtiene algún tipo de volcado de console sobre las restricciones), elija Depurar -> Ver debugging -> Captura de la jerarquía de vistas.

    La aplicación se detiene y se muestra su jerarquía de vista. Seleccione una vista y se le muestra su dirección de memory en el Inspector de objects. Cuando encuentras la que tiene la dirección 0x8675309 , esa es la única. Además, puede ver las restricciones que posicionan esta vista en el Inspector de tamaño.

  2. Implementar las herramientas de registrador de restricciones que proporciono en mi libro. El segundo informa la jerarquía de vista junto con los identificadores y las restricciones.

Estas son las utilidades; entre ellos, he ahorrado horas de perplejidad:

 extension NSLayoutConstraint { class func reportAmbiguity (var v:UIView?) { if v == nil { v = UIApplication.shanetworkingApplication().keyWindow } for vv in v!.subviews as [UIView] { println("\(vv) \(vv.hasAmbiguousLayout())") if vv.subviews.count > 0 { self.reportAmbiguity(vv) } } } class func listConstraints (var v:UIView?) { if v == nil { v = UIApplication.shanetworkingApplication().keyWindow } for vv in v!.subviews as [UIView] { let arr1 = vv.constraintsAffectingLayoutForAxis(.Horizontal) let arr2 = vv.constraintsAffectingLayoutForAxis(.Vertical) NSLog("\n\n%@\nH: %@\nV:%@", vv, arr1, arr2); if vv.subviews.count > 0 { self.listConstraints(vv) } } } } 

Erica Sadun tiene una sugerencia bastante interesante en su libro sobre NSLayout ( iOS Auto Layout Demystified ). UIView tiene una propiedad 'tag' que solo puede aceptar un NSInteger. Con una categoría diseñada apropiadamente en UIView (o, de hecho, en NSObject) podemos agregar una propiedad "viewName" que acepte una cadena con los objects asociados:

 //UIView+viewName.h #import <UIKit/UIKit.h> @interface UIView (NameTagO) - (NSString*)viewName; - (void)setViewName:(NSString*)viewName; @end //UIView+viewName.m #import "UIView+viewName.h" #import <objc/runtime.h> @implementation UIView (viewName) - (NSString*)viewName { return (NSString*)objc_getAssociatedObject(self, @selector(viewName)); } - (void)setViewName:(NSString*)name { NSParameterAssert([viewName isKindOfClass:NSString.class]); objc_setAssociatedObject(self , @selector(viewName) , name , OBJC_ASSOCIATION_RETAIN_NONATOMIC); } 

Luego puede agregar una label de cadena a una vista:

  UIView* view = [UIView alloc] init..]; view.viewName = @"name"; 

explotación florestal:

  NSLog(%@"view: %@",view.viewName) 

Hay una muy buena explicación concisa de los objects asociados en el blog NSHipster que acaba de ser revisado para Swift

Aquí hay una versión rápida de la categoría viewName :

 import Foundation import UIKit extension UIView { private struct AssociatedKeys { static var viewName = "foundry_viewName" } var viewName: String? { get { return objc_getAssociatedObject(self, &AssociatedKeys.viewName) as? String } set { if let newValue = newValue { objc_setAssociatedObject( self, &AssociatedKeys.viewName, newValue as NSString?, UInt(OBJC_ASSOCIATION_RETAIN_NONATOMIC) ) } } } } 

También podría ser una categoría en NSObject, aunque en este context es su uso en UIView lo que nos interesa. Con esta categoría, puede dar a sus vistas tags significativas para fines de logging y extracción. Por ejemplo, podría usar este enfoque junto con el registrador que Matt describe en su respuesta (que proviene de su libro realmente completo sobre iOS ) para registrar vistas usando nombres significativos.

Al crear una vista, establecerá su viewName:

 let view: UIView = UIView.init() view.viewName = "test" 

Entonces, la function de reportAmbiguity de Matt se podría ampliar un poco:

 class func reportAmbiguity (var v:UIView?) { if v == nil { v = UIApplication.shanetworkingApplication().keyWindow } for vv in v!.subviews as [UIView] { let viewName = vv.viewName? if (viewName != nil) { println("\view \(vv.viewName) \(vv.hasAmbiguousLayout())") } else { println("\(vv) \(vv.hasAmbiguousLayout())") } if vv.subviews.count > 0 { //self.reportAmbiguity(vv) } } } 

La única molestia es tener que desempacar el viewName opcional. No tiene que hacer esto, pero si no lo hace, la interpolación de cadenas informará 'Opcional ("testing")', que es un poco engorroso.

Llegué un poco tarde a la fiesta, pero espero que esto ayude. De hecho, hay un atributo extremadamente simple en UIView, a través de su conformidad con UIAccessibilityIdentification :

 centerView.accessibilityIdentifier = "Center Foobar View" containerView.accessibilityIdentifier = "Container BingBat View" 

Esto produce la salida del depurador como era de esperar:

"<NSLayoutConstraint:0x7fe3fa3ade50 Center Foobar View.centerX == Container BingBat View.centerX (Names: Center Foobar View:0x7fe3fa3a1700, Container BingBat View:0x7fe3fa3856c0 )>" ,