概述

  • 老项目是 OC 语言实现了,引用了 Swift 框架。
  • 新项目是 Swift 实现的,引用了 OC 框架,目前微信 SDK,支付宝 SDK 等都是 OC 实现 所以还需要学习一些相关知识。

如何实现

  • 通过官方提供桥接文件这种机制实现。

兼容性

  • 不论是 OC 项目调用 Swift,还是反过来都无法使用所有语法。
    • 例如:OC 项目调用 Swift,无法使用 Swift 的泛型,枚举,结构体等。
    • 反过来,Swift 项目调用 OC,无法使用 OC 的宏定义,指针等。
    • 但是,可以使用桥接文件,将 OC 的头文件引入到 Swift 项目中,这样就可以使用 OC 的所有语法了。
    • 但是,如果是 Swift 项目调用 OC,OC 项目调用 Swift,都可以使用桥接文件,但是,OC 项目调用 Swift,无法使用 Swift 的泛型,枚举,结构体等。

OC 调用 Swift

  • 创建Swift文件,类继承NSObject,方法和字段前面加@objc,如果不加OC中无法调用,但编译不报错。

  • 创建桥接文件,第一次创建 Swift 文件时,会提示是否创建桥接文件,可以点击自动创建;又可以稍后手动创建,手动创建,还要开启在target-Build Settings-All中,找到Defines Module,设置为Yes;同样在 Swift 项目中第一次创建 OC 文件时也会提示。

  • 在要使用 Swift 类的文件中调入自动生成的 Swift 兼容文件,和桥接文件。

  • Swift 文件

//  目的是测试在OC中调用这个类的方法和字段
//  一个Swift如果要在OC中使用,必须继承NSObject
//  其他内容(方法,字段)如果要在OC中使用,前面必须加@objc
//  注意:更改完代码,一定要要编译,OC那边才能引用

import Foundation

class TestSwiftObject: NSObject {
    @objc var var1 = "这是变量1"
    @objc let let1:String = "这是常量"
    @objc static let staticLet:String = "这是静态常量"

    /// 静态计算属性
    @objc open class var staticComputer1: String {
        get{
            let result = 18*10
            return "这是静态的计算属性\(result)"
        }
    }

    /// 静态计算属性
    @objc open var computer1: String {
        get{
            let result = 20*12
            return "这是计算属性\(result)"
        }
    }

    /// 懒加载字段
    @objc lazy var lazyField1: String = {
        let result = 20*12
        print("TestSwiftObject lazyField1 这里的逻辑只会执行一次")
        return "这是懒加载字段\(result)"
    }()

    /// 静态登录方法
    /// - Parameters:
    ///   - name: <#name description#>
    ///   - age: <#age description#>
    /// - Returns: <#description#>
    @objc static func login(name:String,age:Int) -> String {
        return "TestSwiftObject login \(name) \(age)"
    }

    /// 静态登录方法,方法的参数名省略了
    /// - Parameters:
    ///   - name: <#name description#>
    ///   - age: <#age description#>
    /// - Returns: <#description#>
    @objc static func login2(_ name:String,_ age:Int) -> String {
        return "TestSwiftObject login2 \(name) \(age)"
    }

    /// 登录方法
    /// - Parameters:
    ///   - name: <#name description#>
    ///   - age: <#age description#>
    /// - Returns: <#description#>
    @objc func login11(name:String,age:Int) -> String {
        return "TestSwiftObject login11 \(name) \(age)"
    }

    /// 登录方法,方法的参数名省略了
    /// - Parameters:
    ///   - name: <#name description#>
    ///   - age: <#age description#>
    /// - Returns: <#description#>
    @objc func login12(_ name:String,_ age:Int) -> String {
        return "TestSwiftObject login12 \(name) \(age)"
    }
}
  • 要使用导入桥接文件
//导入桥接文件
#import "TestOCUseSwift-Bridging-Header.h"

//如果当前项目有Swift文件,需要在targets的Build Settings将Defines Module设置为YES
//然后编译项目,就会自动生成该文件,这个文件在Xcode中看不到,但可以直接引用
//引用以后,才能在当前文件使用当前项目的Swift源码里面的内容
#import "TestOCUseSwift-Swift.h"

  • 使用 Swift 类
//-------------方法测试
//调用Swift类中的静态方法
NSString *result = [TestSwiftObject loginWithName:@"这是名称" age:20];
NSLog(@"%@",result);

//Swift类中的静态方法,方法参数名称省略了
result=[TestSwiftObject login2:@"这是名称2" :30];
NSLog(@"%@",result);

//调用Swift类中的实例方法
TestSwiftObject *testObject = [[TestSwiftObject alloc] init];
result = [testObject login11WithName:@"这是名称11" age:11];
NSLog(@"%@",result);

//调用Swift类中的实例方法,方法参数名称省略了
result = [testObject login12:@"这是名称12" :12];
NSLog(@"%@",result);

//-------------字段
NSLog(@"静态常量字段:%@",TestSwiftObject.staticLet);
NSLog(@"常量:%@",testObject.let1);
NSLog(@"变量:%@",testObject.var1);

//-------------计算属性
NSLog(@"静态计算属性:%@",TestSwiftObject.staticComputer1);
NSLog(@"计算属性:%@",testObject.computer1);

//-------------懒加载字段
NSLog(@"懒加载:%@",testObject.lazyField1);
NSLog(@"懒加载:%@",testObject.lazyField1);

  • 可以看到能正常调用,像 Swift 中的枚举,结构体就不再演示了,目前是没法使用的,预计以后也不可能兼容。

OC 调用 Swift 第三方框架

  • 通过 Pod 安装 Swift 第三方框架,例如:Chartsopen in new window 框架,他是一个使用 Swift 语言编写的图表框架,他是兼容 OC 调用才能调用,所以并不是所有 Swift 框架都能在 OC 中使用,这一步是正常使用

  • 在桥接文件中导入第三方框架的头文件

//在这个文件导入第三方Swift框架模块
@import Charts;
  • 使用: 例如折线图
//显示一个折线图

//设置代理,通过他可以监听一些事件
_chartView.delegate = self;

//要显示的数据,例如:模拟爱学啊1~6月份,收入金额
NSArray *datas = @[@30,@40,@80,@70,@20,@20,@30];

NSMutableArray *array = [NSMutableArray array];
for (int i=0; i<datas.count; i++) {
    //创建ChartDataEntry对象并将每个点对应的值与x轴 y轴进行绑定
    //x就是月份,y就是值
    ChartDataEntry *entry = [[ChartDataEntry alloc] initWithX:i+1 y:[datas[i] intValue]];
    [array addObject:entry];
}

//创建一个集合并为这个集合赋值 label的值可为空
LineChartDataSet *set = [[LineChartDataSet alloc] initWithEntries:array label:@"收入金额"];

//创建容器
LineChartData *chartData = [[LineChartData alloc] initWithDataSet:set];

self.chartView.data = chartData;

//以动画的方式绘制折线,动画持续2.5秒
[_chartView animateWithXAxisDuration:2.5];

swift 调用 OC

  • 创建 OC 类
// TestObject.h
#import <Foundation/Foundation.h>


NS_ASSUME_NONNULL_BEGIN

//普通宏,可以在 Siwft 中访问
#define ICON_WIDTH 1228

//复杂宏
#define SCEREEN_WIDTH [[UIScreen mainScreen] bounds].size.width

//这是一个常量
static NSString \* const ICON_NAME = @"ixuea";

@interface TestObject : NSObject

@property (strong,nonatomic) NSString \*var1;

/// 静态登录方法
/// @param name <#name description#>
/// @param age <#age description#>
+(NSString _)loginWithName:(NSString _)name age:(int)age;

/// 登录方法
/// @param name <#name description#>
/// @param age <#age description#>
-(NSString _)login11WithName:(NSString _)name age:(int)age;

@end

NS_ASSUME_NONNULL_END

// TestObject.m

#import "TestObject.h"

@implementation TestObject

- (instancetype)init{
    self = [super init];

    if (self) {
        _var1 = [NSString stringWithFormat:@"%@ %@",@"这是变量1",ICON_NAME];
    }
    return self;
}

+ (NSString *)loginWithName:(NSString *)name age:(int)age{
    return [NSString stringWithFormat:@"TestObject static loginWithName %@ %d",name,age];
}

- (NSString *)login11WithName:(NSString *)name age:(int)age{
    return [NSString stringWithFormat:@"TestObject login11WithName %@ %d",name,age];
}

@end


  • 导入头文件,TestSwiftUseOC-Bridging-Header.h

//导入OC头文件,当前项目的,第三方框架的都要导入
#import "TestObject.h"

  • 使用类
//调用OC类中的静态方法
var result=TestObject.login(withName: "这是名称", age: 20)
print(result)

//调用OC类中的实例方法
let testObject = TestObject()
result = testObject.login11(withName: "这是名称11", age: 11)
print(result)

//-------------字段
print("变量:\(testObject.var1)")
print("常量:\(ICON_NAME)")

//-------------宏,只能访问普通的宏,复杂的宏不能访问
print("简单宏:\(ICON_WIDTH)")
//print("访问复杂宏:\(SCEREEN_WIDTH)")

Swift 调用 OC 第三方框架

  • 添加依赖: 例如这里使用微信 SDK 作为演示,目前微信 SDK 是 OC 实现了
#微信sdk,OC实现的
#https://developers.weixin.qq.com/doc/oplatform/Mobile_App/Access_Guide/iOS.html
pod 'WechatOpenSDK'
  • 在桥接文件中导入, TestSwiftUseOC-Bridging-Header.h
//微信SDK
#import <WechatOpenSDK/WXApi.h>
  • 使用
WXApi.registerApp("", universalLink: "")