gpt4 book ai didi

ios - 替换 iOS ViewControllers 部分功能的好策略

转载 作者:行者123 更新时间:2023-11-29 11:32:25 26 4
gpt4 key购买 nike

我在一个 iOS 应用程序中有 VC,它有很多 UI 控件。我现在需要在特定状态下替换或“模拟”其中一些控件。在某些情况下,这只是禁用按钮操作,但在某些情况下,需要用完全不同的东西替换发生的操作。

我真的不喜欢在代码库中散布这种检查的想法。

if condition {
...Special/disabled functionality
} else {
...Normal functionality
}

在 Android 中,我可以将每个 Fragment/Activity 子类化并在那里构建功能,然后在插入 Fragment 或启动 Activity 时执行 if/else。

但是在带有 Storyboards/IBActions 和 Segues 的 iOS 上,UI 和 VC 确实是紧密耦合的。您最终要么复制 UI View ,要么向已经很大的 VC 添加大量挑剔的代码。

在 iOS 中处理此问题的最佳方法是什么?

我想避免做的事情的示例代码:

//Before:
class SomeViewController : UIViewController {
@IBAction onSomeButton() {
checkSomeState()
doANetworkRequest(() -> {
someCompletionHandler()
updatesTheUI()
}
updateTheUIWhileLoading()
}

@IBAction onSomeOtherButton() {
checkAnotherState()
updateUI()
}
}
//After:
class SomeViewController : UIViewController {
@IBAction onSomeButton() {
if specialState {
doSomethingSimpler()
} else {
checkSomeState()
doANetworkRequest(() -> {
someCompletionHandler()
updatesTheUI()
}
updateTheUIWhileLoading()
}
}

@IBAction onSomeOtherButton() {
if specialState {
return // Do nothing
} else {
checkAnotherState()
updateUI()
}
}
}

最佳答案

我建议使用 MVVM (Model - View - ViewModel) pattern .您将 ViewModel 传递给您的 Controller 并将所有操作委托(delegate)给它。您还可以使用它来设置 View 样式,并决定是否应隐藏或禁用其中一些 View 等。

让我们想象一个购物应用程序,您的专业用户可以在其中享受 10% 的折扣并可以使用免费送货选项。

protocol PaymentScreenViewModelProtocol {
var regularPriceString: String { get }
var discountedPriceString: String? { get }
var isFreeShippingAvailable: Bool { get }

func userSelectedFreeShipping()
func buy()
}

class StandardUserPaymentScreenViewModel: PaymentScreenViewModelProtocol {
let regularPriceString: String = "20"
let discountedPriceString: String? = nil
let isFreeShippingAvailable: Bool = false

func userSelectedFreeShipping() {
// standard users cannot use free shipping!
}

func buy() {
// process buying
}
}

class ProUserPaymentScreenViewModel: PaymentScreenViewModelProtocol {
let regularPriceString: String = "20"
let discountedPriceString: String? = "18"
let isFreeShippingAvailable: Bool = true

func userSelectedFreeShipping() {
// process selection of free shipping
}

func buy() {
// process buying
}
}

class PaymentViewController: UIViewController {

@IBOutlet weak var priceLabel: UILabel!
@IBOutlet weak var discountedPriceLabel: UILabel!
@IBOutlet weak var freeShippingButton: UIButton!

var viewModel: PaymentScreenViewModelProtocol

override func viewDidLoad() {
super.viewDidLoad()

priceLabel.text = viewModel.regularPriceString
discountedPriceLabel.text = viewModel.discountedPriceString
freeShippingButton.isHidden = !viewModel.isFreeShippingAvailable
}

@IBAction func userDidPressFreeShippingButton() {
viewModel.userSelectedFreeShipping()
}

@IBAction func userDidPressBuy() {
viewModel.buy()
}
}

这种方法让您可以将逻辑与 View 分离。测试这个逻辑也更容易。
要考虑和决定的一件事是如何将 View 模型注入(inject) View Controller 的方法。我可以看到三种可能性:

  1. 通过 init - 您提供需要传递 View 模型的自定义初始化程序。这将意味着您将无法使用 seguestoryboards(您将能够使用 xib)。这将使您的 View 模型成为非可选的。
  2. 通过具有默认实现的属性设置 - 如果您提供 View 模型的某种形式的默认/空实现,您可以将其用作它的默认值,并在以后设置正确的实现(例如在 prepareForSegue)。这使您能够使用 seguestoryboard 并使 View 模型成为非可选的(它只是增加了额外的空实现的开销)。
  3. 通过没有默认实现的属性设置 - 这基本上意味着您的 View 模型需要是可选的,并且您几乎每次访问它时都必须检查它。

关于ios - 替换 iOS ViewControllers 部分功能的好策略,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52198830/

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