如何定义一个函数,该函数返回一个元素数组,这些元素的类型可以有所不同,但都必须符合某些协议规则?

斯科蒂刀片

我发现在多个 UIViewController 中,我设置了各种可重用视图的访问权限,以便它们可以相应地更新其约束。我想创建一个UIViewController名为SuperClass 的超级类,ChallengeFlowViewController以便它可以负责管理更新轴的调用以支持轴更新的视图。挑战就在于此。我如何定义一个方法或计算属性,以便它可以被覆盖并且子类可以返回任意数量的不同视图,只要这些视图中的每一个都符合 HasViewModel 并且它们的 ViewModel 类型符合 HasAxis。

下面的实现有axisSettables(),但是它的实现方式,它要求返回的所有视图都是相同的视图类型。我希望允许视图类型的差异,只要它们都符合要求。

另一个问题,在viewWillLayoutSubView方法中,我收到错误:Generic parameter 'T' could not be inferred


class ChallengeFlowViewController: UIViewController {

    /// override to ensure axises are set for views that adjust when rotated.
    /// Styles the views if they conform to
    func axisSettables<T: HasViewModel>() -> [T?] where T.ViewModel: HasAxis  {
        []
    }

    override func viewWillLayoutSubviews() {
        super.viewWillLayoutSubviews()
        for view in axisSettables() {
            view?.setAxis()
        }
    }
}



protocol HasViewModel {

    associatedtype ViewModel
    var viewModel: ViewModel { get set }
    init()
}

extension HasViewModel {

    init(viewModel: ViewModel) {
        self.init()
        self.viewModel = viewModel
    }

    mutating func setAxis(
        from newAxis: NSLayoutConstraint.Axis = UIApplication.orientationAxis
    ) where ViewModel: HasAxis {
        guard viewModel.axis != newAxis else { return }
        viewModel.axis = newAxis
    }
}

extension UIApplication {

    /// This is orientation as it relates to constraints.
    enum ConstraintOrientation {
        /// portrait and portraitUpsideDown equal portrait
        case portrait

        /// landscapeleft and landscaperight equal landscape
        case landscape
    }

    /// Unfortunately `UIDevice.current.orientation` is unreliable in determining orientation.
    /// if you `print(UIDevice.current.orientation)` when the simulator or phone launches
    /// with landscape, you will find that the print value can sometimes print as portrait.
    /// if statusBarOrientation is unknown or nil the fallback is portrait, as it would be the safer orientation
    /// for people who have difficulty seeing, for example, if a view's landscape setting splits the views in half
    /// horizontally, the same would look narrow on portrait, wheras the portrait setting is more likely to span
    /// the width of the window.
    static var constraintOrientation: ConstraintOrientation {
        guard #available(iOS 13.0, *) else {
            return UIDevice.current.orientation.constraintOrientation
        }
        return statusBarOrientation == .landscapeLeft || statusBarOrientation == .landscapeRight ? .landscape : .portrait
    }

    @available(iOS 13.0, *)
    static var statusBarOrientation: UIInterfaceOrientation? {
        shared.windows.first(where: \.isKeyWindow)?.windowScene?.interfaceOrientation
    }

    static var orientationAxis: NSLayoutConstraint.Axis {
        constraintOrientation == .landscape ? .horizontal : .vertical
    }
}

protocol HasAxis {

    var axis: NSLayoutConstraint.Axis { get set }
}

extension HasAxis {
    var horizontal: Bool { axis == .horizontal }
    var vertical: Bool { axis == .vertical }
}


克里斯提克

阻止您使用异构数组的是HasViewModel协议,它具有关联的类型,它迫使您将其用作axisSettables函数的通用参数,这导致必须将返回类型声明为同构数组。

如果您希望能够使用异构数组,那么您将需要使用与该协议互补的“常规”协议HasViewModel例如:

protocol AxisSettable {
    func setAxis()
}

class ChallengeFlowViewController: UIViewController {

    /// override to ensure axises are set for views that adjust when rotated.
    /// Styles the views if they conform to
    func axisSettables() -> [AxisSettable] {
        []
    }

这样你也可以将关注点分开,因为axisSettables不应该关心返回的视图是否有视图模型,它应该只关心视图是否可以更新它们的轴。在实现级别,您可以保留HasViewModel协议,如果这对其他领域有帮助,只需添加对AxisSettable.

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章