21.6 Swift调用Objective-C实现的计算器

除了使用纯Swift和纯Objective-C开发计算器应用之外,我们还可以使用Swift和Objective-C两种语言混合搭配来实现计算器应用。混合搭配可以有两种模式,一种是以Swift语言为主,以Objective-C语言为辅;另一种是以Objective-C语言为主,以Swift语言为辅。使用这两种模式的前提是你的应用采用了分层设计架构。

应用程序的运行过程是先启动表示层的视图,然后由表示层响应用户事件,调用业务逻辑层进行计算,计算结果再返回表示层展示出来。因此所谓的“主”就是表示层由谁来担当,所谓的“辅”就是业务逻辑层由谁来担当。

基于分层架构设计下的两种混合搭配模式分别是:

  • 表示层使用Swift,业务逻辑层使用Objective-C,Swift调用Objective-C。

  • 表示层使用Objective-C,业务逻辑层使用Swift,Objective-C调用Swift。

本节我们先介绍Swift调用Objective-C的情况。

21.6.1 在Swift工程中添加Objective-C类

如果我们已经有一个使用Swift语言编写的工程,还需要调用其他Objective-C类实现某些功能,那就可以充分地利用以前使用Objective-C编写的代码。

下面我们具体在Swift版计算器工程中添加Objective-C的CalcLogic类。右键选择Calculator组,选择菜单中的“New File…”弹出新建文件模板对话框。如图21-35所示,选择iOS→Source→Cocoa Touch Class。

{%}

图 21-35 选择文件模板

接着单击“Next”按钮,随即出现图21-36所示的界面。在Class中输入“CalcLogic”,在Language中选择Objective-C,其他的项目保持默认值就可以了。

{%}

图 21-36 新建Objective-C类

设置完相关选项后,单击“Next”按钮,进入保存文件界面,根据提示选择存放文件的位置,然后单击“Create”按钮创建Objective-C类。

如果工程中没有桥接头文件,那么在添加Objective-C类的时候,Xcode会提示我们是否添加,弹出如图21-37所示的对话框,我们应该选择“Yes”,就会在Calculator工程中创建桥接头文件Calculator-Bridging-Header.h。

{%}

图 21-37 创建桥接头文件

然后将被Swift调用的所有Objective-C类的头文件在桥接头文件中引入。Calculator-Bridging- Header.h代码如下:

  1. //
  2. // Use this file to import your target's public headers that you would like to expose to Swift.
  3. //
  4. #import "CalcLogic.h"

在本例中,只引入了CalcLogic.h一个头文件。

21.6.2 调用代码

事实上,如果Swift和Objective-C两端的方法命名很规范,我们几乎不需要修改什么就可以调用了。这里主要需要修改Swift端的ViewController.swift代码:

  1. import UIKit
  2. class ViewController: UIViewController {
  3. @IBOutlet var mainLabel: UILabel
  4. var logic : CalcLogic!
  5. override func viewDidLoad() {
  6. super.viewDidLoad()
  7. mainLabel.text = "0"
  8. logic = CalcLogic()
  9. }
  10. override func didReceiveMemoryWarning() {
  11. super.didReceiveMemoryWarning()
  12. logic = nil
  13. }
  14. @IBAction func operandPressed(sender: AnyObject) {
  15. var btn : UIButton = sender as UIButton
  16. mainLabel.text = logic.calculateByTag(CInt(btn.tag),
  17. withMainLabelString: mainLabel.text)
  18. }
  19. @IBAction func equalsPressed(sender: AnyObject) {
  20. var btn : UIButton = sender as UIButton
  21. mainLabel.text = logic.calculateByTag(CInt(btn.tag),
  22. withMainLabelString: mainLabel.text)
  23. }
  24. @IBAction func clearPressed(sender: AnyObject) {
  25. mainLabel.text = "0";
  26. logic.clear()
  27. }
  28. @IBAction func decimalPressed(sender: AnyObject) {
  29. if logic.doesStringContainDecimal(mainLabel.text) == false {
  30. let string = mainLabel.text + "."
  31. mainLabel.text = string
  32. }
  33. }
  34. @IBAction func numberButtonPressed(sender: AnyObject) {
  35. var btn : UIButton = sender as UIButton
  36. mainLabel.text = logic.updateMainLabelStringByNumberTag(CInt(btn.tag),
  37. withMainLabelString: mainLabel.text)
  38. }
  39. }

上述代码第①~④行调用了Objective-C类CalcLogic,其中第①行代码是调用CalcLogic的如下方法:

  1. -(NSString*)calculateByTag:(int) tagwithMainLabelString:(NSString*)mainLabelString

要注意Objective-C中方法的命名,以及在Swift中调用的方法名和参数要对应,它们的对应关系如图21-38所示。

{%}

图 21-38 方法命名对应关系

Objective-C类CalcLogic中方法命名是采用多重参数的,方法名的第一部分名calculateByTag就是在Swift调用时的方法名,CalcLogic中其他部分名,如withMainLabelString是在Swift调用时的外部参数名。

代码编写完成后,我们可以运行一下看看效果。