【问题标题】:iOS-Swift Dynamic UIViewController use with multiple custom defined attribute typeiOS-Swift 动态 UIViewController 与多个自定义属性类型一起使用
【发布时间】:2020-05-25 11:19:10
【问题描述】:

所以我有一个 ViewController 有一个类型为“Something”的属性,这个相同的视图控制器我想将它与类型为“something1”的不同属性一起使用,我正在考虑为每个自定义类型“something”制定一个协议" 和 "something1" 并且它们会在 ViewController 中提供我需要的东西,但它们都是结构,并且它们都不起作用,因为它们都是值类型。

我的示例代码如下:

final class DynamicViewController: UIViewController {

private let attribute: CustomType // something or Somthing1
private let stackView: UIStackView

init(attribute: CustomType) {
    self.attribute = attribute
    super.init(nibName: nil, bundle: nil)
}

required init?(coder: NSCoder) {
    fatalError("init(coder:) has not been implemented")
}

override func viewDidLoad() {
    super.viewDidLoad()
    setupViews()
}

private func setupViews() {
    let scrollView = UIScrollView()
    scrollView.translatesAutoresizingMaskIntoConstraints = false
    view.addSubview(scrollView)

    NSLayoutConstraint.activate ([
        ...
    ])

    scrollView.addSubview(stackView)

    NSLayoutConstraint.activate([
    ...
    ])

    getInfoLabels()
}

private func getInfoLabels() {
    if let attribute = attribute {
        numerateInObjectAndGetLabel(obj: attribute)
    }
}

private func numerateInObjectAndGetLabel(obj: Any) {
    let mirroredAttr = Mirror(reflecting: obj)
    for (_, attr) in mirroredAttr.children.enumerated() {
        if let txts = attr.value as? [String] {
            for txt in txts {
                stackView.addArrangedSubview(getLabel(for: txt))
            }
        }
    }
}

private func getLabel(for text: String) -> UILabel {
    let label = UILabel()
    ....
    return label
}}

我确实有使用多种自定义类型制作多个可选属性的解决方案,但在我的情况下,我有超过 10 种自定义类型,所以它会变得丑陋..

有没有办法用简洁干净的方法解决这个问题?我真的不喜欢冗余代码。

【问题讨论】:

    标签: ios swift generics dynamic swift-protocols


    【解决方案1】:

    因此,作为解决方案,我创建了一个协议并将其定义在结构中,但我必须使结构不可编码,因为在我的情况下不是问题,如果这是一个问题,那么您可以使用 init(from:) 和带有编码键。

    然后我让我的 DynamicViewController 扩展了该协议,当然我需要将结构委托(协议)设置为视图控制器。

    答案:

    let dynamicViewController = DynamicViewController()
        something.delegate = dynamicViewController
        navigationController?.pushViewController(abuseOverdosageViewController, animated: true)
    
    ------------------------------------------------------------
    
    final class DynamicViewController: UIViewController, CustomProtocol {
    
    private let stackView: UIStackView
    
    init(attribute: CustomType) {
        self.attribute = attribute
        super.init(nibName: nil, bundle: nil)
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    override func viewDidLoad() {
        super.viewDidLoad()
        setupViews()
    }
    
    private func setupViews() {
        let scrollView = UIScrollView()
        scrollView.translatesAutoresizingMaskIntoConstraints = false
        view.addSubview(scrollView)
    
        NSLayoutConstraint.activate ([
            ...
            ])
    
        scrollView.addSubview(stackView)
    
        NSLayoutConstraint.activate([
            ...
            ])
    }
    
    /// PROTOCOL
    func getView(view: UIView) {
        stackView.addArrangedSubview(view)
       }
    }
    -------------------------------------------
    
    
    protocol CustomProtocol {
       func getView(view: UIView)
    }
    
    
    -------------------------------------------
    struct Something {
    
    public var delegate: CustomProtocol? {
        didSet {
            numerateInObjectAndGetLabel(obj: self)
        }
    }
    
    /// attributes
    public var ......
    public var .....
    public var ....
    public var ...
    public var ..
    
    
    private func numerateInObjectAndGetLabel(obj: Any) {
        let mirroredAttr = Mirror(reflecting: obj)
        for (_, attr) in mirroredAttr.children.enumerated() {
            if let txts = attr.value as? [String] {
                for txt in txts {
                    delegate?.getView(view: getLabel(for: txt))
                }
            }
        }
    }
    
    private func getLabel(for text: String) -> UILabel {
        let label = UILabel()
        ...
        return label
       }
    }
    

    【讨论】:

      【解决方案2】:

      我认为最好的办法是将变量“属性”更改为协议,然后使用类实现此协议。

      顺便说一句:

      final class DynamicView: UIViewController
      

      你应该把它重命名为:

      DynamicViewController
      

      因为它的类型是 UIViewController,而不是 UIView。

      【讨论】:

      • 感谢您的提示,但这不是真正的代码;),但会编辑问题。
      • 好的,但还是这样。我认为你应该将协议作为变量,然后你的“SomethingTypes”应该实现这个协议。
      • 所以为了更清楚地将这两个属性作为表示 JSON struct Something: Codable {...} 的结构,协议将不起作用。正如我在问题中已经说过的那样。但请纠正我,也许我不理解你。
      • 结构可以实现很多协议。只需使用:struct Something: Codable, Somethingable {...} 为什么您认为协议在这里不起作用?
      • 啊,好吧,我想反了;在结构内部定义协议,视图控制器将扩展协议。我在结构中施展魔法,委托方法将在视图控制器中触发。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-07-23
      • 1970-01-01
      • 1970-01-01
      • 2014-05-21
      • 1970-01-01
      • 1970-01-01
      • 2011-01-14
      相关资源
      最近更新 更多