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

在上一节我们实现了Swift调用Objective-C,现在我们再来介绍一下Objective-C调用Swift实现。

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

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

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

{%}

图 21-39 选择文件模板

接着单击“Next”按钮,随即出现如图21-40所示的界面。在Class中输入“CalcLogic”,Subclass of(继承自)项目选择NSObject,在Language中选择Swift,其他的项目保持默认值就可以了。

{%}

图 21-40 新建Swift类

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

21.7.2 调用代码

从Objective-C调用Swift不需要桥接头文件。在Objective-C端,视图控制器ViewController的代码基本上不需要修改,但是要想访问Swift对象还是需要引入一个头文件,这个文件的命名是 <工程名>-Swift.h,那么就需要在ViewController.h文件中引入头文件,ViewController.h代码如下:

  1. #import <UIKit/UIKit.h>
  2. #import "Calculator-Swift.h" ①
  3. @interface ViewController : UIViewController
  4. {
  5. CalcLogic *logic;
  6. }
  7. @property (weak, nonatomic) IBOutlet UILabel *mainLabel;
  8. - (IBAction)operandPressed:(id)sender;
  9. - (IBAction)equalsPressed:(id)sender;
  10. - (IBAction)clearPressed:(id)sender;
  11. - (IBAction)decimalPressed:(id)sender;
  12. - (IBAction)numberButtonPressed:(id)sender;
  13. @end

上述代码第①行引入了头文件Calculator-Swift.h,这样Objective-C就可以访问工程中的Swift类了。

此外,还需要修改一下Swift端的代码,Swift端的CalcLogic.swift代码如下:

  1. import Foundation
  2. enum Operator : Int {
  3. case Plus = 200, Minus, Multiply, Divide
  4. case Default = 0
  5. }
  6. @objc class CalcLogic : NSObject {
  7. //保存上一次的值
  8. var lastRetainValue : Double
  9. //最近一次选择的操作符(加、减、乘、除)
  10. var opr : Operator
  11. //临时保存MainLabel内容,为true时,输入数字MainLabel内容被清为0
  12. var isMainLabelTextTemporary : Bool
  13. /*
  14. * 构造器
  15. */
  16. override init () {
  17. println("CalcLogic init")
  18. lastRetainValue = 0.0
  19. isMainLabelTextTemporary = false
  20. opr = .Default
  21. }
  22. /*
  23. * 析构器
  24. */
  25. deinit {
  26. println("CalcLogic deinit")
  27. }
  28. /*
  29. * 判断字符串中是否包含.
  30. */
  31. func updateMainLabelStringByNumberTag(tag : Int, withMainLabelString
  32. mainLabelString : String)->String {
  33. var string = mainLabelString
  34. if (isMainLabelTextTemporary) {
  35. string = 0
  36. isMainLabelTextTemporary = false
  37. }
  38. let optNumber = tag - 100
  39. //把String转为double
  40. var mainLabelDouble = (string as NSString).doubleValue
  41. if mainLabelDouble == 0 && doesStringContainDecimal(string) == false {
  42. return String(optNumber)
  43. }
  44. let resultString = string + String(optNumber)
  45. return resultString
  46. }
  47. /*
  48. * 判断字符串中是否包含小数点
  49. */
  50. func doesStringContainDecimal(string : String)->Bool {
  51. for ch in string {
  52. if ch == "." {
  53. return true
  54. }
  55. }
  56. return false
  57. }
  58. /*
  59. * 点击操作符时的计算
  60. */
  61. func calculateByTag(tag : Int, withMainLabelString mainLabelString : String)->String {
  62. //把String转为double
  63. var currentValue = (mainLabelString as NSString).doubleValue
  64. switch Operator {
  65. case .Plus:
  66. lastRetainValue += currentValue
  67. case .Minus:
  68. lastRetainValue -= currentValue
  69. case .Multiply:
  70. lastRetainValue *= currentValue
  71. case .Divide:
  72. if currentValue != 0 {
  73. lastRetainValue /= currentValue
  74. } else {
  75. opr = .Default
  76. isMainLabelTextTemporary = true
  77. return "错误"
  78. }
  79. Default:
  80. lastRetainValue = currentValue
  81. }
  82. //记录当前操作符,下次计算时使用
  83. opr = Operator(rawValue:tag)!
  84. let resultString = NSString(format: "%g", lastRetainValue)
  85. isMainLabelTextTemporary = true
  86. return resultString
  87. }
  88. func clear() {
  89. lastRetainValue = 0.0
  90. isMainLabelTextTemporary = false
  91. opr = .Default
  92. }
  93. }

上述代码与纯Swift版本变化不是很大。但是需要注意代码第①行,CalcLogic类继承了NSObject类,而纯Swift版本中的CalcLogic类是没有继承任何父类的。再有我们在类前面声明为@objc,这也是与纯Swift版本的区别,@objc所声明的类能够被Objective-C访问,@objc还可以修饰属性。代码第②行override init()是重写NSObject父类构造器init()

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