作为一个IOS软件开发者,遇到混编也是常有之事,本文通过一个简单的数字时钟示例,展示如何通过中间文件达到目的,实现混编。
本文创建的是一个OC项目,但是实际上OC项目和Swift项目混编是差不多的,下面上货。
一、创建或导入任意混编文件,生成或创建OC桥接头文件
新建混编文件时(如OC项目中新建Swift文件或Swift项目中新建OC文件),Xcode 会提示创建桥接头文件,生成的头文件名为
ModuleName-Bridging-Header.h,为Swift调用OC代码之用。如下例图:
图 1.1
也可以自行创建桥接头文件,然后在 TARGETS >> Build Settings 下进行配置对应路径
图1.2
二、OC项目如何调用Swift代码
导入或创建Swift文件后,Xcode会自动生成可依赖的接口文件,命名为
ModuleName-Swift.h, 如图1.2所示的IOS_App-Swift.h,编译时会更新该头文件。
需要调用Swift代码,导入该头文件即可,如:
#import "ProductModuleName-Swift.h"
需要注意的是Swift包含
===================本文所使用Swift代码如下:
import Foundation
@objc protocol UpdateObserver {
func update ()
}
@objc class HelloWorldTimer :NSObject{
fileprivate var updateObserver : UpdateObserver?
fileprivate var isUpdating : Bool = false
override init() {
super.init()
}
func printLog ( _ printString :String ) -> Void{
print("\(AppDelegate.getAppId()!): \(printString)")
}
func getNowTimeString () -> String{
let date = NSDate()
let timeFormatter = DateFormatter()
timeFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss"//yyyy-MM-dd HH:mm:ss.SSS
return timeFormatter.string(from: date as Date) as String
}
func registerTimerChangeObserver (obs : UpdateObserver ){
updateObserver = obs
}
func startTimer(){
isUpdating = true
timeUpdatePerSecond()
}
func isTimeUpdating () -> Bool{
return self.isUpdating
}
func endTimer() {
isUpdating = false
}
@objc fileprivate func timeUpdatePerSecond() {
guard isUpdating else {
return
}
if let o = updateObserver {
o.update()
}
perform(#selector(timeUpdatePerSecond), with: nil, afterDelay: 1)
}
}
请注意,上面代码中的class和protocol都添加了
@objc属性
这样才能被OC项目调用。
=====================OC代码调用Swift代码
#import <UIKit/UIKit.h>
#import "IOS_App-Swift.h"
@interface ViewController : UIViewController <UpdateObserver>
@end
#import "ViewController.h"
#import "IOS_App-Swift.h"
@interface ViewController ()
{
UILabel *time;
HelloWorldTimer *world;
}
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
world = [[HelloWorldTimer alloc]init];
[world registerTimerChangeObserverWithObs:self];
time = [[UILabel alloc]initWithFrame:CGRectZero];
time.translatesAutoresizingMaskIntoConstraints = false;
time.text = [world getNowTimeString];
time.font = [UIFont systemFontOfSize:33];
time.textColor = [UIColor blueColor];
NSLayoutConstraint * timeCentreXConstraint = [NSLayoutConstraint constraintWithItem:time attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeCenterX multiplier:1.0f constant:0];
NSLayoutConstraint * timeCentreYConstraint = [NSLayoutConstraint constraintWithItem:time attribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeCenterY multiplier:1.0f constant:0];
[self.view addSubview:time];
[self.view addConstraints:@[timeCentreXConstraint,timeCentreYConstraint]];
NSNotificationCenter* ns = [NSNotificationCenter defaultCenter];
[ns addObserver:self selector:@selector(applicationDidBecomeActive) name:UIApplicationDidBecomeActiveNotification object:nil];
[ns addObserver:self selector:@selector(applicationWillResignActive) name:UIApplicationWillResignActiveNotification object:nil];
}
- (void)applicationDidBecomeActive {
[world startTimer];
[world printLog:@"applicationDidBecomeActive"];
}
- (void) applicationWillResignActive {
if ([world isTimeUpdating]){
[world endTimer];
}
[world printLog:@"applicationWillResignActive"];
}
- (void)update {
time.text = [world getNowTimeString];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
@end
三、OC项目中Swift文件调用OC代码
OC和Swift代码可以相互调用,但是一个OC文件调用了Swift代码,则该文件不能被Swift代码调用,反之亦然
把相关头文件加入桥接头文件(
ModuleName-Bridging-Header.h)即可
================IOS-App-Bridging-Header.h内容
//
// Use this file to import your target's public headers that you would like to expose to Swift.
//
#import "AppDelegate.h"
================Swift文件调用的OC相关代码
#import <UIKit/UIKit.h>
#import <CoreData/CoreData.h>
@interface AppDelegate : UIResponder <UIApplicationDelegate>
@property (strong, nonatomic) UIWindow *window;
@property (readonly, strong) NSPersistentContainer *persistentContainer;
- (void)saveContext;
+ (NSString *) getAppId;
@end
//.....
@implementation AppDelegate
+ (NSString *)getAppId {
return @"IOS-App";
}
//.......
=======================Swift代码调用OC代码,从上面的Swift代码中截取如下
func printLog ( _ printString :String ) -> Void{
print("\(AppDelegate.getAppId()!): \(printString)")
}
效果截图
相关Log打印:
IOS-App: applicationDidBecomeActive
IOS-App: applicationWillResignActive