【问题标题】:Dynamically reference an IBOutlet in Swift?在 Swift 中动态引用 IBOutlet?
【发布时间】:2017-04-01 23:06:32
【问题描述】:

我有一个包含 100 个 IBOutlet 的视图控制器,我想根据是否在 Dictionary 中找到该 IBOutlet 的名称作为键来隐藏或显示它们。

我到底该怎么做呢?我的直觉告诉我

for item in Dict {
    // try to refer to an IBOutlet using data from my Dictionary 
    self.\(item.key).hidden = false
}

当我尝试这样做时,Swift 显然会抛出错误。

我对此很陌生,甚至不知道该怎么称呼我正在尝试做的事情。甚至有可能做到这一点吗?有没有更好的方法来做到这一点?

我想避免写 100 个“if”语句。

【问题讨论】:

  • 我很确定拥有 100 甚至 40 个网点表明您的架构存在一些非常糟糕的问题。按名称访问变量是另一种反模式。请分享更多您的代码,我们可以然后帮助您解决真正的问题
  • 我有 100 个方形 UIView,它们出现在特定位置的 View Controller 中。我想根据数据动态显示或隐藏它们。我知道我可以以编程方式绘制它们,但我相信这也意味着以编程方式编写 400 个约束(高度、宽度、X 位置、Y 位置),这听起来非常痛苦和复杂。
  • 这绝对比在 IB 中创建数百个约束要容易。另请注意,您不必使用自动布局。这是使用简单的旧自动调整大小会更简单的情况之一。即使为所有视图创建约束也需要大约 30 行。此外,在使用 IB 时,您仍然可以将所有插座连接到一个阵列中,然后按位置对其进行排序。您将拥有 1 个插座而不是 100 个插座,并且您可以使用简单的索引。
  • 就我自己的理解而言,“使用自动布局”是什么意思?这是否意味着“使用界面生成器”?还是指别的东西?
  • autolayout = 显式约束,autoresizing = 使用没有约束的帧,带有自动调整掩码(帧在内部转换为约束),现在仅在代码中使用。

标签: swift iboutlet


【解决方案1】:

应该有很多其他更好的方法来做到这一点。

  1. 您是否考虑将所有出口添加到字典中?

    var outletDict: [String: UIView] = ["outlet1": outlet1, "outlet2": outlet2,
        "outlet3", outlet3 ... "outlet100": outlet100]
    

然后您可以使用 this 字典访问网点:

for item in Dict {
    outletDict[item.key].hidden = false
}
  1. 您是否尝试过不使用 outlet 而是动态创建视图?我的意思是,拥有 100 个网点真的很少见。我想知道你是如何将它们连接起来的。它们应该是某种模式或其他东西。如果是这样,您可以使用 for 循环创建视图并将它们添加到上述字典中。

  2. 如果以上都不适用于你,我能想到的唯一解决方案是:

    for item in Dict {
        let mirror = Mirror(reflecting: self)
        let outlet = mirror.children.filter { $0.label == item.key }.first?.value as? UIView
        outlet?.hidden = false
    }
    

【讨论】:

  • 插座是方形 UIViews,图案略显复杂。以编程方式将它们添加为子视图感觉就像我可以弄清楚的事情。以编程方式生成 400 个约束感觉非常令人生畏。
  • 如果它们是像网格一样的方格视图,您是否考虑过使用UICollectionView? @bflora2
  • 这不是一个精确的网格。它有一个奇怪的、不均匀的形状。
  • @bflora2 我刚刚意识到您可以使用标签:将每个视图的tag 设置为IB 中的唯一值,然后您可以使用viewWithTag 来获取视图。你的Dict 可以是[Int: UIView] 而不是[String: UIView]
【解决方案2】:

我同意 Sulthan 的观点,即这是一个限制条件,而 IB 是糟糕的设计。我将其编码为模板,应该可以帮助您。备注:

  • 全局宽度和高度变量便于更改。编码实践不佳,但用于测试目的。
  • 我将子视图的创建从 backgroundColor 选项中分离出来,让您了解如何快速迭代子视图。
  • 您可能不需要“seedValue”部分。我需要它来区分行。
  • 最重要的是,由于您只声明您有 100 个“UIView”,因此我建议将 UIView 子类化为某种东西。您不仅可以创建方便的初始化程序(使初始化附加属性和公共子视图变得容易),还可以将超级视图的子视图作为您的子类类型进行迭代,从而允许您在其他地方使用标记属性。

代码:

let width:CGFloat = 20
let height:CGFloat = 20

override func viewDidLoad() {
    super.viewDidLoad()
    create100subviews()
    for view in view.subviews as [UIView] {
        color(view)
    }
}

func create100subviews() {
    for i in 1...100 {
        let newView = UIView(frame: calculateFrame(width: width, height: height, tag: i))
        newView.tag = i
        view.addSubview(newView)
    }
}

func calculateFrame(width:CGFloat, height:CGFloat, tag:Int) -> CGRect {
    let (row,column) = calculateRowAndColumn(tag: tag)
    return CGRect(x: ((CGFloat(column)*width)+20), y: ((CGFloat(row)*height)+40), width: width, height: height)
}

func calculateRowAndColumn(tag:Int) -> (Int,Int) {
    // the returned tuple (row,column) is zero-based
    var row:Int = 0
    var column = tag
    while column > 10 {
        row += 1
        column -= 10
    }
    column -= 1
    return (row,column)
}

func color(_ view: UIView) {
    let (row,column) = calculateRowAndColumn(tag: view.tag)
    var seedValue = column + row + 1
    while seedValue > 10 {
        seedValue -= 10
    }
    switch seedValue {
    case 1:
        view.backgroundColor = UIColor.black
    case 2:
        view.backgroundColor = UIColor.red
    case 3:
        view.backgroundColor = UIColor.green
    case 4:
        view.backgroundColor = UIColor.blue
    case 5:
        view.backgroundColor = UIColor.black
    case 6:
        view.backgroundColor = UIColor.red
    case 7:
        view.backgroundColor = UIColor.green
    case 8:
        view.backgroundColor = UIColor.blue
    case 9:
        view.backgroundColor = UIColor.black
    case 10:
        view.backgroundColor = UIColor.red
    default:
        break
    }
}

【讨论】:

  • 我最终以编程方式绘制它们。花了大约 4 个小时才弄清楚如何实施约束,但现在可以了。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-11-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多