Swift:如何重用视图控制器

时间:2022-01-21 08:21:12

I am working on a simple custom converter app. The problem is that I have created a separate view controller for each (!) conversion (fahrenheit to celsius, ounces to kilograms and so on) and I would like to know how I could re-use only one converter view controller and just change the calculations done in the background?

我工作在一个简单的自定义转换器应用。问题是,我已经创建了一个单独的视图控制器(!)转换(华氏摄氏度,盎司公斤等等),我想知道我可以重用只有一个转换器视图控制器,只改变计算在后台做了什么?

This is what I have done so far:

这是我迄今为止所做的:

  • mainVC (contains buttons for each converter viewController)
  • mainVC(包含每个转换器视图控制器的按钮)
  • (right now 10) converter VCs for each conversion the user can do
  • (现在)转换器vc为用户可以做的每一次转换
  • MathLib.swift with different functions for each math formula
  • MathLib。每个数学公式都有不同的函数

Each converter VC contains a name label (eg. ounce to kilogram), a number pad and an input/output label. When the user touches a number the conversion is done on the fly with the right math formula from MathLib.swift. I just use the corresponding formula with a return. This is an example of a formula:

每个转换器VC包含一个名称标签(如。一盎司到千克),一个数字板和一个输入/输出标签。当用户触摸一个数字时,转换就会动态地使用MathLib.swift提供的正确数学公式进行。我只是用相应的公式来表示返回。这是一个公式的例子:

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

Now what I want to do is just having one(!) converter VC and depending on the button pressed in mainVC the right formula is used in MathLib and the name of the label is changed to the right conversion type.

现在我要做的就是有一个(!)转换器VC,取决于mainVC中按下的按钮,在MathLib中使用了正确的公式,标签的名称改为正确的转换类型。

  1. All buttons should point to just one VC. Now when a button is pressed and the view controller is presented how can I check from which button the user comes? For example the button name or tag?

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

  2. When I know the button name or tag how can I use this to use the right formula in MathLib.swift or change the name label? Do I have to use a switch case? If so: how can I set up the switch case to check for the button used and then point to the right math function and change the name label?

    当我知道按钮名称或标记时,我如何使用它来在MathLib中使用正确的公式。斯威夫特还是改名字?我必须用开关吗?如果是:如何设置开关情况,以检查所使用的按钮,然后指向正确的数学函数并更改名称标签?

In short: Using just one VC, checking for which button brought the user to this VC and then using something (switch case?) to change some things like labels on the VC and use the right function in a library.swift file.

简而言之:只使用一个VC,检查哪个按钮将用户带到这个VC中,然后使用某个东西(switch case?)来改变VC中的标签,并在库中使用正确的函数。快速文件。

This is quite difficult for me and if you could help me I'd appreciate this.

这对我来说很困难,如果你能帮我,我会很感激的。

2 个解决方案

#1


2  

You are on the right track.

你在正确的轨道上。

Now that you can get which button was clicked, like you said by name or the tag (i prefer the second, think of when you'll be making your app available in different languages, i.e localization).

现在,你可以得到哪个按钮被点击了,就像你所说的按名字或标签(我更喜欢第二个按钮,想想什么时候你会让你的应用以不同的语言可用,i。e本地化)。

Your main view controller should now only contain an input, and a button, and may be a title for the screen, to know which conversion is being used.

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

As for the calculation (the business logic), i would recommend that you define a protocol that has one method called convert that takes one argument, being the value the user would want to convert.

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

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

and then create as much classes as there are conversions to be made, let me take only one example and keep it as simple as possible, consider the converter meters to kilometers.

然后创建尽可能多的要转换的类,我只举一个例子,尽可能简单地考虑从米到千米的转换。

let's call it DistanceConverter that should implement the Converter protocol

我们称它为DistanceConverter,它应该实现转换器协议

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

Now when you tap the button from the first screen called meter to kilometers, in your handler you would :

当你从第一个叫做米到千米的屏幕上点击按钮时,你的处理器会:

1) instantiate an instance of the DistanceConverter.

1)实例化DistanceConverter的实例。

2) instatiante an instance of MainViewController. and give it the DistanceConverter instance you created in step 1.

2)安装MainViewController的一个实例。并为它提供第1步中创建的DistanceConverter实例。

3) keep a reference of the DistanceConverter as an iVar in your mainViewController.

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

the key point here is to keep it in an iVar of type Converter, so it can hold all the instances of any class that would implement the Converter protocol you will be creating.

这里的关键点是将它保存在类型转换器的iVar中,这样它就可以容纳任何类的所有实例来实现您将要创建的转换器协议。

4) in the handler of the button 'convert' of the mainViewController you call the method convert on the mainViewController 's iVar that you made in step 3.

4)在mainViewController的按钮“转换”的处理程序中,你调用mainViewController的iVar上的方法转换,这是你在步骤3中做的。

And so now in order for you to create another converter, let's say TemperatureConverter that handles Celcius to Fahrenheit, you create a new class :

现在为了让你创建另一个转换器,比方说温度转换器它可以处理华氏温度,你创建了一个新类:

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

When you tap the button temerature on the first screen: 1) instantiate an instance of the DistanceConverter. and then keep repeat all the remaining steps as before (you can easily refactore all the rest of the steps).

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

This is the Strategy pattern out of the box, so i recommend you read about it and it's application with swift.

这是一种开箱即用的策略模式,因此我建议您阅读有关它的文章,并使用swift进行应用。

#2


-1  

You should pass a delegate to the view controller where the conversion happens, which implements the function you want to use. When you instantiate the view controller before you push or present it, inject the delegate.

您应该将委托传递给视图控制器,其中转换发生,实现了您想要使用的函数。当您在推送或呈现视图控制器之前实例化它时,注入委托。

Define a protocol with a protocol-method for each method you want to use and then let the delegate implement them via an extensions. The delegate can be even be the ViewController that allows to select a conversion type.

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

You can then define an enum with your conversion type and also pass it to the new view controller. On your view controller just switch over the type and run the correct delegate method.

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

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
}

On your destination view controller:

在你的目标视图控制器:

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
        }
    }
}

#1


2  

You are on the right track.

你在正确的轨道上。

Now that you can get which button was clicked, like you said by name or the tag (i prefer the second, think of when you'll be making your app available in different languages, i.e localization).

现在,你可以得到哪个按钮被点击了,就像你所说的按名字或标签(我更喜欢第二个按钮,想想什么时候你会让你的应用以不同的语言可用,i。e本地化)。

Your main view controller should now only contain an input, and a button, and may be a title for the screen, to know which conversion is being used.

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

As for the calculation (the business logic), i would recommend that you define a protocol that has one method called convert that takes one argument, being the value the user would want to convert.

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

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

and then create as much classes as there are conversions to be made, let me take only one example and keep it as simple as possible, consider the converter meters to kilometers.

然后创建尽可能多的要转换的类,我只举一个例子,尽可能简单地考虑从米到千米的转换。

let's call it DistanceConverter that should implement the Converter protocol

我们称它为DistanceConverter,它应该实现转换器协议

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

Now when you tap the button from the first screen called meter to kilometers, in your handler you would :

当你从第一个叫做米到千米的屏幕上点击按钮时,你的处理器会:

1) instantiate an instance of the DistanceConverter.

1)实例化DistanceConverter的实例。

2) instatiante an instance of MainViewController. and give it the DistanceConverter instance you created in step 1.

2)安装MainViewController的一个实例。并为它提供第1步中创建的DistanceConverter实例。

3) keep a reference of the DistanceConverter as an iVar in your mainViewController.

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

the key point here is to keep it in an iVar of type Converter, so it can hold all the instances of any class that would implement the Converter protocol you will be creating.

这里的关键点是将它保存在类型转换器的iVar中,这样它就可以容纳任何类的所有实例来实现您将要创建的转换器协议。

4) in the handler of the button 'convert' of the mainViewController you call the method convert on the mainViewController 's iVar that you made in step 3.

4)在mainViewController的按钮“转换”的处理程序中,你调用mainViewController的iVar上的方法转换,这是你在步骤3中做的。

And so now in order for you to create another converter, let's say TemperatureConverter that handles Celcius to Fahrenheit, you create a new class :

现在为了让你创建另一个转换器,比方说温度转换器它可以处理华氏温度,你创建了一个新类:

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

When you tap the button temerature on the first screen: 1) instantiate an instance of the DistanceConverter. and then keep repeat all the remaining steps as before (you can easily refactore all the rest of the steps).

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

This is the Strategy pattern out of the box, so i recommend you read about it and it's application with swift.

这是一种开箱即用的策略模式,因此我建议您阅读有关它的文章,并使用swift进行应用。

#2


-1  

You should pass a delegate to the view controller where the conversion happens, which implements the function you want to use. When you instantiate the view controller before you push or present it, inject the delegate.

您应该将委托传递给视图控制器,其中转换发生,实现了您想要使用的函数。当您在推送或呈现视图控制器之前实例化它时,注入委托。

Define a protocol with a protocol-method for each method you want to use and then let the delegate implement them via an extensions. The delegate can be even be the ViewController that allows to select a conversion type.

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

You can then define an enum with your conversion type and also pass it to the new view controller. On your view controller just switch over the type and run the correct delegate method.

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

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
}

On your destination view controller:

在你的目标视图控制器:

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
        }
    }
}