gpt4 book ai didi

ios - 在 MVVM 和 MVC 模式中在哪里创建 View ?

转载 作者:搜寻专家 更新时间:2023-11-01 06:34:14 24 4
gpt4 key购买 nike

如有重复请见谅

我通常在没有 Storyboard的情况下编写我的应用程序,并将 View 创建放入“viewDidLoad”,例如:

class LoginVC: UIViewController {

var view1: UIView!
var label1: UILabel!

override func viewDidLoad() {
super.viewDidLoad()

loadStaticViews()
}

func loadStaticViews() {
view1 = UIView()
label1 = UILabel()
view.addSubview(view1)
view1.addSubview(label1)
// constraints...
}
}

现在我想在我的下一个应用程序中尝试 MVVM 模式,只是不确定在哪里创建 View 。现在我想到了类似的事情:

class LoginVCViews {
static func loadViews<T, T1, T2>(superview: UnsafeMutablePointer<T>, view: UnsafeMutablePointer<T1>, label: UnsafeMutablePointer<T2>) {
guard let superview = superview.pointee as? UIView else { return }
let v = UIView()
let l = UILabel()
superview.addSubview(v)
v.addSubview(l)

// constraints...

view.pointee = v as! T1
label.pointee = l as! T2
}
}

class LoginVC: UIViewController {

private var view1: UIView!
private var label1: UILabel!

override func viewDidLoad() {
super.viewDidLoad()
LoginVCViews.loadViews(superview: &view, view: &view1, label: &label1)
}
}

你怎么看?我对 UnsafeMutablePointer 不是很熟悉并且不确定不会有一些问题。它有多丑?

最佳答案

也许您应该尝试完全面向对象的路径。 View 组合看起来像这样:

//可重用协议(protocol)集

protocol OOString: class {
var value: String { get }
}

protocol Executable: class {
func execute()
}

protocol Screen: class {
var ui: UIViewController { get }
}

protocol ViewRepresentation: class {
var ui: UIView { get }
}

//可重用功能(无 uikit 依赖)

final class ConstString: OOString {

init(_ value: String) {
self.value = value
}

let value: String

}

final class ExDoNothing: Executable {

func execute() { /* do nothing */ }

}

final class ExObjCCompatibility: NSObject, Executable {

init(decorated: Executable) {
self.decorated = decorated
}

func execute() {
decorated.execute()
}

private let decorated: Executable

}

//可重用的 UI(uikit 依赖)

final class VrLabel: ViewRepresentation {

init(text: OOString) {
self.text = text
}

var ui: UIView {
get {
let label = UILabel()
label.text = text.value
label.textColor = UIColor.blue
return label
}
}

private let text: OOString

}

final class VrButton: ViewRepresentation {

init(text: OOString, action: Executable) {
self.text = text
self.action = ExObjCCompatibility(decorated: action)
}

var ui: UIView {
get {
let button = UIButton()
button.setTitle(text.value, for: .normal)
button.addTarget(action, action: #selector(ExObjCCompatibility.execute), for: .touchUpInside)
return button
}
}

private let text: OOString
private let action: ExObjCCompatibility

}

final class VrComposedView: ViewRepresentation {

init(first: ViewRepresentation, second: ViewRepresentation) {
self.first = first
self.second = second
}

var ui: UIView {
get {
let view = UIView()
view.backgroundColor = UIColor.lightGray
let firstUI = first.ui
view.addSubview(firstUI)
firstUI.translatesAutoresizingMaskIntoConstraints = false
firstUI.topAnchor.constraint(equalTo: view.topAnchor, constant: 100).isActive = true
firstUI.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 20).isActive = true
firstUI.widthAnchor.constraint(equalToConstant: 100).isActive = true
firstUI.heightAnchor.constraint(equalToConstant: 40).isActive = true
let secondUI = second.ui
view.addSubview(secondUI)
secondUI.translatesAutoresizingMaskIntoConstraints = false
secondUI.topAnchor.constraint(equalTo: firstUI.topAnchor).isActive = true
secondUI.leadingAnchor.constraint(equalTo: firstUI.trailingAnchor, constant: 20).isActive = true
secondUI.widthAnchor.constraint(equalToConstant: 80).isActive = true
secondUI.heightAnchor.constraint(equalToConstant: 40).isActive = true
return view
}
}

private let first: ViewRepresentation
private let second: ViewRepresentation

}

//一个 View Controller

final class ContentViewController: UIViewController {

convenience override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) {
self.init()
}

convenience required init(coder aDecoder: NSCoder) {
self.init()
}

convenience init() {
fatalError("Not supported!")
}

init(content: ViewRepresentation) {
self.content = content
super.init(nibName: nil, bundle: nil)
}

override func loadView() {
view = content.ui
}

private let content: ViewRepresentation

}

//现在是屏幕的业务逻辑(不可重用)

final class ScStartScreen: Screen {

var ui: UIViewController {
get {
return ContentViewController(
content: VrComposedView(
first: VrLabel(
text: ConstString("Please tap:")
),
second: VrButton(
text: ConstString("OK"),
action: ExDoNothing()
)
)
)
}
}

}

在 AppDelegate 中的用法:

window?.rootViewController = ScStartScreen().ui

注意:

  • 它遵循面向对象编码的规则(干净的编码、优雅的对象、装饰器模式,...)
  • 每个类的构造都非常简单
  • 类之间通过协议(protocol)进行通信
  • 所有依赖尽可能通过依赖注入(inject)给出
  • 一切(除了最后的业务屏幕)都是可重用的 -> 事实上:可重用代码的组合随着你编码的每一天而增长
  • 您应用的业务逻辑集中在 Screen 对象的实现中
  • 当对协议(protocol)使用虚假实现时,单元测试非常简单(在大多数情况下甚至不需要模拟)
  • 较少的保留周期问题
  • 避免 Null、nil 和 Optionals(它们会污染您的代码)
  • ...

在我看来,这是最好的编码方式,但大多数人不会那样做。

关于ios - 在 MVVM 和 MVC 模式中在哪里创建 View ?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43424548/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com