您可以在不使用 Storyboard 的情况下在 AutoLayout 控制台输出中标记视图吗?

Posted

技术标签:

【中文标题】您可以在不使用 Storyboard 的情况下在 AutoLayout 控制台输出中标记视图吗?【英文标题】:Can you label views in AutoLayout console output without using Storyboards? 【发布时间】:2015-01-28 22:35:00 【问题描述】:

我正在观看关于 AutoLayout 的 WWDC 演讲,并且我了解到,在视图上设置 StoryboardID 可以使控制台输出的约束冲突更容易阅读(即,您得到一个名称而不仅仅是一个地址)。他们向您展示了在 Interface Builder 中设置 StoryboardID(以前只是“标识符”)的位置,但是有没有办法在代码中做到这一点?我正在尝试调试我自己没有编写的大量复杂视图,在一个 100% 编程的应用程序中,有许多无法满足的约束,并且(以某种方式)在 ios 7 中工作但开始在 iOS 中中断8. 我很想清楚是哪个<UIView:0x8675309> 实际导致了问题。

我查看了 UIView 类参考,没有找到“标识符”或“StoryboardID”。

如果答案是“不”,也不会太惊讶。毕竟它被称为 Storyboard ID 是有原因的。但如果可能的话,我希望能得到确认,以及使 AutoLayout 控制台转储更具可读性的解决方法。

【问题讨论】:

显然这个故事中没有故事板所以没有故事板ID。您真正想知道什么?我的意思是,这似乎与在控制​​台中识别视图有关,对吗?那么为什么不问那个呢?解释真正的问题是什么。你想做什么,为什么做不到? 因为 WWDC 的谈话说这样做的方法是在 IB 中设置标识符。我会改写我的问题。 IMO,应用程序 100% 编程没有任何问题。我都做过,如果您要维护产品一段时间,我更喜欢它是程序化的。 @matt - 我认为您过于苛刻了,我阅读了标题并完全了解问题是什么以及为什么解决方案有用 // 更正 ...此评论发布于 Garret 编辑问题后! @matt 感谢您帮助我解决问题! 【参考方案1】:

我参加聚会有点晚了,但我希望这会有所帮助。 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 )>",

【讨论】:

嘿,我不再做 Objective-C 了,但这看起来正是我当时正在寻找的东西。谢谢! 干杯!我知道这对我有帮助 :-) 当您暂停调试器时,我实际上是在寻找使用什么来在 View Hierarchy 列表中标记它们 - 结果是不同的 - 可访问性标签。【参考方案2】:

我很想清楚地了解问题的真正原因。

我有两个建议。

    在 Xcode 中,在应用程序的同一运行期间(最好是在您获得某种关于约束的控制台转储之后),选择 Debug -> View Debugging -> Capture View Hierarchy。

    应用暂停,您将看到您的视图层次结构。选择一个视图,您会在 Object Inspector 中看到它的内存地址。当您找到地址为0x8675309 的那个时,就是那个。此外,您还可以在 Size Inspector 中查看定位此视图的约束。

    实现我在书中提供的约束记录器实用程序。第二个报告视图层次结构以及标识符和约束。

这里是实用程序;在他们之间,我节省了数小时的困惑:

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)
            
        
    

【讨论】:

使用 Capture View Heirarchy 功能将视图映射到地址的概念正是我所需要的。谢谢!【参考方案3】:

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,刚刚是revisited for Swift

这里是 viewName 类别的 swift-ified 版本:

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”)',这有点麻烦。

【讨论】:

感谢您的日志记录想法,我会试一试。

以上是关于您可以在不使用 Storyboard 的情况下在 AutoLayout 控制台输出中标记视图吗?的主要内容,如果未能解决你的问题,请参考以下文章

我可以在不使用 xml 文件的情况下在列表视图中添加视图吗

如何在不使用对话框的情况下在操作栏上方显示视图?

如何在不使用“|”的情况下在一行中连接两个集合

如何在不使用count(*)的情况下在greenplum中查找表中的行数

在不安装 Visual Studio 的情况下在机器上调试代码

如何在不使用滞后的情况下在偏移量旁边显示一列值