我发现在多个 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] 删除。
我来说两句