您可以在不使用 Storyboard 的情况下在 AutoLayout 控制台输出中标记视图吗?
Can you label views in AutoLayout console output without using Storyboards?
我正在观看有关 AutoLayout 的 WWDC 演讲,我了解到在您的视图上设置 StoryboardID 可以使约束冲突的控制台输出更容易阅读(即您得到一个名称而不仅仅是一个地址).他们向您展示了在 Interface Builder 中设置 StoryboardID(以前只是 "Identifier")的位置,但是有没有办法在代码中进行设置?我正在尝试在一个 100% 程序化的应用程序中调试大量复杂的视图,这些视图不是我自己编写的,它有许多无法满足的约束,并且(以某种方式)在 iOS 7 中工作但是开始闯入 iOS 8。我很想清楚地了解 <UIView:0x8675309>
到底是哪个问题造成的。
我查看了 UIView class 参考,找不到 "Identifier" 或 "StoryboardID"。
如果答案是 "nope",也不会太惊讶。毕竟它被称为 Storyboard ID 是有原因的。但如果可能的话,我将不胜感激确认和解决方法,以使 AutoLayout 控制台转储更具可读性。
I would love to get a clear picture of which is actually causing the problem.
我有两个建议。
在 Xcode 中,在应用程序的相同 运行 期间(最好是在您获得关于约束的某种控制台转储之后),选择调试 ->查看调试 -> 捕获视图层次结构。
应用程序暂停,您会看到您的视图层次结构。 Select 一个视图,您会在对象检查器中看到它的内存地址。当您找到地址为 0x8675309
的那个时,就是那个。另外,您可以在尺寸检查器中看到定位此视图的约束。
实现我在书中提供的约束记录器实用程序。第二个报告视图层次结构以及标识符和约束。
这是实用程序;在他们之间,我节省了数小时的困惑:
extension NSLayoutConstraint {
class func reportAmbiguity (var v:UIView?) {
if v == nil {
v = UIApplication.sharedApplication().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.sharedApplication().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 在她关于 NSLayout 的书中有一个很酷的建议(iOS Auto Layout Demystified)。 UIView 有一个 'tag' 属性 只能接受一个 NSInteger。通过在 UIView 上(或实际上在 NSObject 上)适当制作的类别,我们可以添加一个 "viewName" 属性 - 它接受一个字符串 - 使用关联的对象:
//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);
}
然后您可以将字符串标记添加到视图中:
UIView* view = [UIView alloc] init..];
view.viewName = @"name";
记录:
NSLog(%@"view: %@",view.viewName)
有一个真的很好简洁explanation of associated objects on the NSHipster blog which has just been revisited for Swift
这是 viewName
类别的 swift 化版本:
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)
)
}
}
}
}
它也可以是 NSObject 上的一个类别,尽管在这种情况下,我们感兴趣的是它在 UIView 上的使用。使用此类别,您可以为视图提供有意义的标签,用于记录和提取目的。例如,您可以将此方法与 Matt 在他的回答(来自他的 really comprehensive book on iOS)中描述的记录器结合使用,以使用有意义的名称记录视图。
创建视图时,您将设置其视图名称:
let view: UIView = UIView.init()
view.viewName = "test"
那么 Matt 的 reportAmbiguity
功能可以稍微扩展一下:
class func reportAmbiguity (var v:UIView?) {
if v == nil {
v = UIApplication.sharedApplication().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)
}
}
}
唯一的烦恼是必须解压 viewName
可选。您 没有 这样做,但如果您不这样做,字符串插值将报告 'Optional("test")' 这有点麻烦。
我来晚了一点,但希望这对您有所帮助。 UIView 确实有一个非常简单的属性,通过它符合 UIAccessibilityIdentification:
centerView.accessibilityIdentifier = "Center Foobar View"
containerView.accessibilityIdentifier = "Container BingBat View"
这会产生您期望的调试器输出:
"<NSLayoutConstraint:0x7fe3fa3ade50 Center Foobar View.centerX == Container BingBat View.centerX (Names: Center Foobar View:0x7fe3fa3a1700, Container BingBat View:0x7fe3fa3856c0 )>"
,
我正在观看有关 AutoLayout 的 WWDC 演讲,我了解到在您的视图上设置 StoryboardID 可以使约束冲突的控制台输出更容易阅读(即您得到一个名称而不仅仅是一个地址).他们向您展示了在 Interface Builder 中设置 StoryboardID(以前只是 "Identifier")的位置,但是有没有办法在代码中进行设置?我正在尝试在一个 100% 程序化的应用程序中调试大量复杂的视图,这些视图不是我自己编写的,它有许多无法满足的约束,并且(以某种方式)在 iOS 7 中工作但是开始闯入 iOS 8。我很想清楚地了解 <UIView:0x8675309>
到底是哪个问题造成的。
我查看了 UIView class 参考,找不到 "Identifier" 或 "StoryboardID"。
如果答案是 "nope",也不会太惊讶。毕竟它被称为 Storyboard ID 是有原因的。但如果可能的话,我将不胜感激确认和解决方法,以使 AutoLayout 控制台转储更具可读性。
I would love to get a clear picture of which is actually causing the problem.
我有两个建议。
在 Xcode 中,在应用程序的相同 运行 期间(最好是在您获得关于约束的某种控制台转储之后),选择调试 ->查看调试 -> 捕获视图层次结构。
应用程序暂停,您会看到您的视图层次结构。 Select 一个视图,您会在对象检查器中看到它的内存地址。当您找到地址为
0x8675309
的那个时,就是那个。另外,您可以在尺寸检查器中看到定位此视图的约束。实现我在书中提供的约束记录器实用程序。第二个报告视图层次结构以及标识符和约束。
这是实用程序;在他们之间,我节省了数小时的困惑:
extension NSLayoutConstraint {
class func reportAmbiguity (var v:UIView?) {
if v == nil {
v = UIApplication.sharedApplication().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.sharedApplication().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 在她关于 NSLayout 的书中有一个很酷的建议(iOS Auto Layout Demystified)。 UIView 有一个 'tag' 属性 只能接受一个 NSInteger。通过在 UIView 上(或实际上在 NSObject 上)适当制作的类别,我们可以添加一个 "viewName" 属性 - 它接受一个字符串 - 使用关联的对象:
//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);
}
然后您可以将字符串标记添加到视图中:
UIView* view = [UIView alloc] init..];
view.viewName = @"name";
记录:
NSLog(%@"view: %@",view.viewName)
有一个真的很好简洁explanation of associated objects on the NSHipster blog which has just been revisited for Swift
这是 viewName
类别的 swift 化版本:
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)
)
}
}
}
}
它也可以是 NSObject 上的一个类别,尽管在这种情况下,我们感兴趣的是它在 UIView 上的使用。使用此类别,您可以为视图提供有意义的标签,用于记录和提取目的。例如,您可以将此方法与 Matt 在他的回答(来自他的 really comprehensive book on iOS)中描述的记录器结合使用,以使用有意义的名称记录视图。
创建视图时,您将设置其视图名称:
let view: UIView = UIView.init()
view.viewName = "test"
那么 Matt 的 reportAmbiguity
功能可以稍微扩展一下:
class func reportAmbiguity (var v:UIView?) {
if v == nil {
v = UIApplication.sharedApplication().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)
}
}
}
唯一的烦恼是必须解压 viewName
可选。您 没有 这样做,但如果您不这样做,字符串插值将报告 'Optional("test")' 这有点麻烦。
我来晚了一点,但希望这对您有所帮助。 UIView 确实有一个非常简单的属性,通过它符合 UIAccessibilityIdentification:
centerView.accessibilityIdentifier = "Center Foobar View"
containerView.accessibilityIdentifier = "Container BingBat View"
这会产生您期望的调试器输出:
"<NSLayoutConstraint:0x7fe3fa3ade50 Center Foobar View.centerX == Container BingBat View.centerX (Names: Center Foobar View:0x7fe3fa3a1700, Container BingBat View:0x7fe3fa3856c0 )>"
,