【问题标题】:Swift: How to re-use view controllerSwift:如何重用视图控制器
【发布时间】:2017-10-25 04:55:45
【问题描述】:

我正在开发一个简单的自定义转换器应用程序。 问题是我为每个(!)转换(华氏到摄氏度,盎司到千克等)创建了一个单独的视图控制器,我想知道如何仅重用一个转换器视图控制器并更改在后台进行计算?

这是我到目前为止所做的:

  • mainVC(包含每个转换器视图控制器的按钮)
  • (现在有 10 个)转换器 VC 用于用户可以进行的每次转换
  • MathLib.swift 为每个数学公式提供不同的函数

每个转换器 VC 都包含一个名称标签(例如,盎司到千克)、一个数字键盘和一个输入/输出标签。当用户触摸一个数字时,转换是使用 MathLib.swift 中正确的数学公式即时完成的。我只是使用相应的公式返回。这是一个公式的例子:

static func stoneToKilo(stone: Double) -> Double {
        let kilo = stone / 0.15747
        return kilo
    }

现在我想做的只是拥有一个(!)转换器 VC,并根据在 mainVC 中按下的按钮,在 MathLib 中使用正确的公式,并将标签的名称更改为正确的转换类型。

  1. 所有按钮都应该只指向一个 VC。现在,当按下按钮并显示视图控制器时,我如何检查用户来自哪个按钮?例如按钮名称或标签?

  2. 当我知道按钮名称或标签时,如何使用它在 MathLib.swift 中使用正确的公式或更改名称标签?我必须使用开关盒吗?如果是这样:如何设置开关盒以检查使用的按钮,然后指向正确的数学函数并更改名称标签?

简而言之:只使用一个 VC,检查是哪个按钮将用户带到了这个 VC,然后使用一些东西(切换大小写?)来改变一些东西,比如 VC 上的标签,并在 library.swift 文件中使用正确的函数.

这对我来说非常困难,如果你能帮助我,我将不胜感激。

【问题讨论】:

  • 您可以从查看NSMeasurement 框架开始,因为它可以为您完成转换。然后你可以有一个单一的视图控制器,你所有的按钮需要做的就是在 VC 上设置适当的输入和输出测量单位属性。

标签: ios swift viewcontroller


【解决方案1】:

你在正确的轨道上。

现在您可以知道点击了哪个按钮,就像您通过名称或标签所说的那样(我更喜欢第二个,想一想您何时会以不同的语言提供您的应用程序,即本地化)。

您的主视图控制器现在应该只包含一个输入和一个按钮,并且可能是屏幕的标题,以了解正在使用的转换。

至于计算(业务逻辑),我建议您定义一个协议,该协议具有一个名为 convert 的方法,该方法接受一个参数,即用户想要转换的值。

protocol Converter {
    func convert( _ value : Double) -> Double
}

然后根据要进行的转换创建尽可能多的类,让我仅举一个示例并使其尽可能简单,以米到公里的转换器为例。

我们称它为 DistanceConverter,它应该实现 Converter 协议

class DistanceConverter : Converter {
    func convert( _ value : Double) -> Double {
         return value / 1000.0
    }
}

现在,当您从第一个屏幕点击米到公里的按钮时,在您的处理程序中,您将:

1) 实例化 DistanceConverter 的实例。

2) 实例化 MainViewController 的一个实例。并给它您在步骤 1 中创建的 DistanceConverter 实例。

3) 将 DistanceConverter 的引用作为 iVar 保存在 mainViewController 中。

这里的关键是将它保存在 Converter 类型的 iVar 中,这样它就可以保存任何将实现您将创建的 Converter 协议的类的所有实例。

4) 在 mainViewController 的按钮“convert”的处理程序中,您在步骤 3 中创建的 mainViewController 的 iVar 上调用方法 convert。

所以现在为了让您创建另一个转换器,假设将处理摄氏度到华氏度的 TemperatureConverter,您创建一个新类:

class TemperatureConverter : Converter {
    func convert( _ value : Double) -> Double {
         // return the calculation, 
    }
}

当您在第一个屏幕上点击按钮温度时: 1) 实例化 DistanceConverter 的一个实例。 然后像以前一样重复所有剩余的步骤(您可以轻松地重构所有剩余的步骤)。

这是开箱即用的策略模式,所以我建议你阅读它以及它的应用程序。

【讨论】:

  • 感谢您的回答。我有几个问题。 1.我可以把协议和类放到另一个swift文件(比如MathLib.swift)吗? 2.我不明白的是实例/处理程序的事情。到目前为止,我只需将 ConverterVC 与 MainVC 连接并使用开关检查按钮标签,并根据它更改标签(等)。当按下转换器按钮时,使用另一个 switch 语句再次检查标签并使用 MathLib.swift 中的相关数学公式函数。这比以前容易得多,但我想你的建议更短!?
  • 处理程序是指您的 IBAction 实现。我所描述的不一定是较短的方法,这不应该是您的主要重点,您应该将重点放在编写随着时间的推移更容易维护的代码上。从长远来看,switch 语句是邪恶的,因此您可以通过使用多态性来避免它们。继续努力:)
【解决方案2】:

您应该将委托传递给发生转换的视图控制器,该控制器实现您要使用的功能。在推送或呈现视图控制器之前实例化视图控制器时,注入委托。

为您要使用的每个方法定义一个带有协议方法的协议,然后让委托通过扩展来实现它们。委托甚至可以是允许选择转换类型的 ViewController。

然后,您可以使用您的转换类型定义一个枚举,并将其传递给新的视图控制器。在您的视图控制器上,只需切换类型并运行正确的委托方法。

enum ConversionType: Int {
    case fahrenheitToCelsius
    // other cases
}

protocol ConversionDelegate {
    func convertToCelsius(fromFahrenheitDegrees fDegrees: Double) → Double
    // other protocol functions
}

// Other protocols here

class SelectionViewController: UIViewController {
    // your usual stuff like viewDidLoad

    func presentConversionViewController(forConversion type: ConversionType) {
        let destinationVC = ... // instantiate your VC from storyboard here
        destinationVC.delegate = self
        destinationVC.conversionType = type
        // present/push your VC
}

extension SelectionViewController: ConversionDelegate {
    func convertToCelsius(fromFahrenheitDegrees fDegrees: Double) → Double {
        // you Math.lib func here
        return (fDegrees - 32) / 1.8 // example
    }
    // implement the other functions
}

在您的目标视图控制器上:

class DestinationViewController: UIViewController {
    var delegate: ConversionDelegate!
    var type: ConversionType!

    // your usual stuff like viewDidLoad

    @IBAction func calculateButtonPressed(_ sender: UIButton) {
        switch type {
            case .fahrenheitToCelsius:
            // read the input value from somewhere like a UITextField
            // most likely you will have to convert a String to Double in the example 
            let result = delegate.convertToCelsius(fromFahrenheitDegrees: yourInputValue) 
            // output the result to some label or whatever you like
        }
    }
}

【讨论】:

  • 为什么每次转化都有单独的协议?似乎一个协议的潜在价值在于拥有几个不同的转换器对象,每个对象都符合相同的协议。但即使这样也显得过于复杂,尤其是在应用程序的其他部分不需要转换代码的情况下。
  • 抱歉,我的想法有点混乱,我更新了答案。
猜你喜欢
  • 1970-01-01
  • 2018-04-04
  • 1970-01-01
  • 2015-09-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-10-12
  • 2011-07-29
相关资源
最近更新 更多