以编程方式快速创建对象数组 3

Posted

技术标签:

【中文标题】以编程方式快速创建对象数组 3【英文标题】:Programmatically create an array of objects swift 3 【发布时间】:2017-06-29 04:15:06 【问题描述】:

我想创建一个水平级联的对象数组,我试图创建一个函数来减小我的代码大小,但是,创建的对象之间似乎可能存在 NSLayoutConstraint 冲突?

这是我的代码

private func createProfileImageContainers(numberOfFriends: Int) 

    for friends in 1...numberOfFriends 

    let imageViewContainer = UIView()
    imageViewContainer.translatesAutoresizingMaskIntoConstraints = false
    imageViewContainer.backgroundColor = UIColor.blue
    imageViewContainer.frame = CGRect(x: 0, y: 0, width: frame.width / 10, height: frame.width / 10)

        NSLayoutConstraint(item: imageViewContainer, attribute: .centerX, relatedBy: .equal, toItem: container, attribute: .centerX, multiplier: CGFloat((1 / 2) + ((friends - 1) / 50 )), constant: 0).isActive = true

        NSLayoutConstraint(item: imageViewContainer, attribute: .centerY, relatedBy: .equal, toItem: container, attribute: .centerY, multiplier: 1, constant: 0).isActive = true

        addSubview(imageViewContainer)
    


这是调试器的意思

乘数 0 或 nil 第二项与第一个属性的位置一起创建了位置等于常数的非法约束。位置属性必须成对指定。'

有什么建议吗?

编辑

感谢 Robs 的回答,我能够解决调试器的问题,但是只添加了一个 imageViewContainer 实例。可能是因为它们都被添加到具有相同名称的视图层次结构中,所以每个新视图都会取代最后一个...... 我认为创建一个类可以解决这个问题,但现在我什么都没有出现。

这是更新后的代码...

class profileImageContainer: UIView 

    let imageViewContainer: UIView = 
    let iv = UIView()
    iv.translatesAutoresizingMaskIntoConstraints = false
    iv.backgroundColor = UIColor.blue


    return iv
()




private func createProfileImageContainers(numberOfFriends: Int) 



    for friends in 1...numberOfFriends 


        print(friends)


        let imageViewContainer = profileImageContainer()


        addSubview(imageViewContainer)

        NSLayoutConstraint(item: imageViewContainer, attribute: .width, relatedBy: .equal, toItem: container, attribute: .width, multiplier: 0.1, constant: 0).isActive = true
        NSLayoutConstraint(item: imageViewContainer, attribute: .height, relatedBy: .equal, toItem: container, attribute: .width, multiplier: 0.1, constant: 0).isActive = true

        NSLayoutConstraint(item: imageViewContainer, attribute: .centerX, relatedBy: .equal, toItem: container, attribute: .centerX, multiplier: 0.5 + (CGFloat(friends - 1) / 50.0), constant: 0).isActive = true


        NSLayoutConstraint(item: imageViewContainer, attribute: .centerY, relatedBy: .equal, toItem: container, attribute: .centerY, multiplier: 1, constant: 0).isActive = true



    


 

【问题讨论】:

更喜欢 UITableView 或 UIStackView 。 不应该 centerX 乘数乘以容器的宽度吗? @NRitH 乘数是一个乘数,它可以是任何数字。那里的代码只是一个占位符 atm,但它仍然应该是有效的。我只是想测试 for in 循环。 对于 luckyShubhra 的观点,如果您想考虑重构它,堆栈视图(如果您不需要滚动能力)可以让您摆脱为所有子视图定义约束。您只需要堆栈视图的约束,将其指定为水平堆栈视图并告诉它均匀排列其排列的视图。然后它将负责安排所有子视图。或者,如果您想要水平滚动功能,您可以使用集合视图。但我知道,如果你想让这个工作,首先。 @luckyShubhra 我要做的就是创建8个圆圈,每个圆圈的左边缘都是前一个圆圈centerx。我可以一个一个地创建每个视图,但这似乎不是最优的。 【参考方案1】:

    一个问题是表达式:

    CGFloat((1 / 2) + ((friends - 1) / 50))
    

    这是进行整数除法,然后将得到的整数转换为CGFloat。实际上,您的表达式将为前 50 个 friends 值返回 0

    您想进行浮点数学运算,在进行除法之前将friends - 1 转换为CGFloat

    0.5 + CGFloat(friends - 1) / 50.0
    

    我还建议您在添加约束之前添加子视图。

    您应该指定宽度和高度约束并取消frame 的设置。 frame 将在应用约束时被丢弃,并且在没有宽度和高度约束的情况下,约束是不明确的。


您的第二个代码示例存在几个问题:

您的ProfileImageContainer 有一个imageViewContainer,但您从不使用它。所以,你不会看到你的ProfileImageContainers(因为你没有设置自己的backgroundColor)。我可以想象你最终可能会用ProfileImageContainerimageViewContainer 属性做一些有意义的事情(例如,将它添加到视图层次结构中,设置图像等)。但是现在,我建议你删除它,因为它只会让情况变得混乱。

即使我们修复了上述问题,子视图也会重叠,因为您已将它们定义为某个容器宽度的 1/10,但您将 centerX 乘数调整了 1/50。

这样做的最终结果是视图将重叠,看起来只有一个存在。但我相信如果你使用视图调试器,你会发现它们都在那里。您需要更改 centerX 约束,使它们不会重叠。

无论如何,这里有一个解决上述问题的版本:

//  SampleView.swift

import UIKit

class ProfileImageContainer: UIView 

    override init(frame: CGRect) 
        super.init(frame: frame)

        configure()
    

    required init?(coder aDecoder: NSCoder) 
        super.init(coder: aDecoder)

        configure()
    

    func configure() 
        translatesAutoresizingMaskIntoConstraints = false
        backgroundColor = .blue
    



class SampleView: UIView 

    var container: UIView!

    override init(frame: CGRect = .zero) 
        super.init(frame: frame)

        configure()
    

    required init?(coder aDecoder: NSCoder) 
        super.init(coder: aDecoder)

        configure()
    

    func configure()  
        container = UIView()
        container.translatesAutoresizingMaskIntoConstraints = false
        addSubview(container)
        NSLayoutConstraint.activate([
            container.leftAnchor.constraint(equalTo: leftAnchor),
            container.rightAnchor.constraint(equalTo: rightAnchor),
            container.topAnchor.constraint(equalTo: topAnchor),
            container.bottomAnchor.constraint(equalTo: bottomAnchor)
        ])

        createProfileImageContainers(numberOfFriends: 5)
    

    var friends = [UIView]()

    private func createProfileImageContainers(numberOfFriends: Int) 

        // remove old friends in case you called this before

        friends.forEach  $0.removeFromSuperview() 
        friends.removeAll()

        // now add friends 

        for friend in 0 ..< numberOfFriends      // easier to go from 0 to numberOfFriends-1 than subtract one later

            print(friend)

            let imageViewContainer = ProfileImageContainer()

            container.addSubview(imageViewContainer)

            NSLayoutConstraint.activate([
                imageViewContainer.widthAnchor.constraint(equalTo: container.widthAnchor, multiplier: 0.1),
                imageViewContainer.heightAnchor.constraint(equalTo: container.heightAnchor, multiplier: 0.1),
                NSLayoutConstraint(item: imageViewContainer, attribute: .centerX, relatedBy: .equal, toItem: container, attribute: .centerX, multiplier: 2 * CGFloat(friend + 1) / CGFloat(numberOfFriends + 1), constant: 0),
                imageViewContainer.centerYAnchor.constraint(equalTo: container.centerYAnchor)
            ])

            friends.append(imageViewContainer)
        

     


【讨论】:

这清除了调试器中的问题,但是我仍然无法创建同一对象的多个实例。请查看更新后的代码。 查看带有代码示例的修订答案。仅供参考,我也在github.com/robertmryan/AddSubviewDemo 发布。请参阅 github.com/robertmryan/AddSubviewDemo/releases 了解我对您的代码所做的编辑。 @Stefan - 坦率地说,与其自己构建这些约束,我建议使用堆栈视图(参见github.com/robertmryan/AddSubviewDemo/tree/UIStackView)。它完全让您摆脱为所有子视图手动定义约束的工作。只需为堆栈视图定义约束,并让它排列其子视图。或者,如果“朋友”的数量可能超过了可以容纳的数量,并且您希望能够滚动浏览它们,请使用集合视图(请参阅github.com/robertmryan/AddSubviewDemo/tree/UICollectionView)。

以上是关于以编程方式快速创建对象数组 3的主要内容,如果未能解决你的问题,请参考以下文章

快速创建类数组

零基础快速掌握JavaScript数组深拷贝与浅拷贝

创建ndarray

More Effective C++ 条款3最好不要以多态方式处理数组

JS创建对象,数组,函数的三种方式

在 C++ 中以编程方式在编译时创建静态数组