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代码如下:
//
// Use this file to import your target's public headers that you would like to expose to Swift.
//
#import "CalcLogic.h"
在本例中,只引入了CalcLogic.h一个头文件。
21.6.2 调用代码
事实上,如果Swift和Objective-C两端的方法命名很规范,我们几乎不需要修改什么就可以调用了。这里主要需要修改Swift端的ViewController.swift代码:
import UIKit
class ViewController: UIViewController {
@IBOutlet var mainLabel: UILabel!
var logic : CalcLogic!
override func viewDidLoad() {
super.viewDidLoad()
mainLabel.text = "0"
logic = CalcLogic()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
logic = nil
}
@IBAction func operandPressed(sender: AnyObject) {
var btn : UIButton = sender as UIButton
mainLabel.text = logic.calculateByTag(CInt(btn.tag),
withMainLabelString: mainLabel.text) ①
}
@IBAction func equalsPressed(sender: AnyObject) {
var btn : UIButton = sender as UIButton
mainLabel.text = logic.calculateByTag(CInt(btn.tag),
withMainLabelString: mainLabel.text) ②
}
@IBAction func clearPressed(sender: AnyObject) {
mainLabel.text = "0";
logic.clear()
}
@IBAction func decimalPressed(sender: AnyObject) {
if logic.doesStringContainDecimal(mainLabel.text) == false { ③
let string = mainLabel.text + "."
mainLabel.text = string
}
}
@IBAction func numberButtonPressed(sender: AnyObject) {
var btn : UIButton = sender as UIButton
mainLabel.text = logic.updateMainLabelStringByNumberTag(CInt(btn.tag),
withMainLabelString: mainLabel.text) ④
}
}
上述代码第①~④行调用了Objective-C类CalcLogic
,其中第①行代码是调用CalcLogic
的如下方法:
-(NSString*)calculateByTag:(int) tagwithMainLabelString:(NSString*)mainLabelString
要注意Objective-C中方法的命名,以及在Swift中调用的方法名和参数要对应,它们的对应关系如图21-38所示。
图 21-38 方法命名对应关系
Objective-C类CalcLogic
中方法命名是采用多重参数的,方法名的第一部分名calculateByTag
就是在Swift调用时的方法名,CalcLogic
中其他部分名,如withMainLabelString
是在Swift调用时的外部参数名。
代码编写完成后,我们可以运行一下看看效果。