Swift和Objective-C互相调用
在Swift 中使用Objective-C
官方文档
桥接文件
桥接文件是一个在Swift中调用OC类或方法的通道。Swift在同模块内文件是可以相互调用的(不能模块之间调用是需要引入模块的),但是OC文件是需要引入头文件才能使用。
在Swift中首次创建OC文件的时候,xcode会弹出一个窗口,询问是否要创建桥接文件。桥接文件默认的命名为 “项目名-Bridging-Header.h”。只需要将OC 的头文件在桥接文件中#import一下就可以在Swift中使用。
如果在询问是否创建桥接文件的时候,没有选择创建,或者不小心将桥接文件删除了,我们也可以在 Targets–>Build Settings–>Swift Compiler - General–>Objective-C Bridging Header中 手动配置。创建一个头文件,文件的命名可以按照自己习惯命名,并不一定需要按照默认桥接文件的命名方式,创建完成后只需要在Targets–>Build Settings–>Swift Compiler - General–>Objective-C Bridging Header中 配置桥接头文件的路径就可以了。
NS_ASSUME_NONNULL_BEGIN 和 NS_ASSUME_NONNULL_END的作用
在Swift中,变量是有可选(optional)和非可选(non-optional)之分的,但是在OC中并没有对一个变量是否是nil进行区分,这就造成一个问题,在 Swift与Objective-C混编时,Swift编译器并不知道一个Objective-C对象到底是optional
还是non-optional
,这种情况下,编译器会默认的将OC对象当成是非可选。
为了解决这个问题,苹果在Xcode 6.3引入了一个Objective-C的新特性:nullability annotations。这一新特性的核心是两个新的类型注释: __nullable 和 __nonnull 。从字面上我们可以猜到,__nullable
表示对象可以是NULL
或nil
,而__nonnull
表示对象不应该为空。当我们不遵循这一规则时,编译器就会给出警告。
但是每个属性或者方法返回值或者参数都去指定是否nullable,实在是太繁琐了,NS_ASSUME_NONNULL_BEGIN 和 NS_ASSUME_NONNULL_END就是为了简化这种操作而诞生的,在这两个宏之间的代码,所有简单指针对象都被假定为nonnull,因此我们只需要去指定那些nullable的指针。
//Person.h
#import <Foundation/Foundation.h>NS_ASSUME_NONNULL_BEGIN@interface Person : NSObject
@property(nonatomic,copy,nullable)NSString *name;
@property(nonatomic,copy)NSString *sex;
-(instancetype)initWithName:(NSString *)name sex:(NSString *)sex;
@endNS_ASSUME_NONNULL_END//Person.m
#import "Person.h"@implementation Person
-(instancetype)initWithName:(NSString *)name sex:(NSString *)sex{if (self = [super init]) {self.name = name;self.sex = sex;}return self;
}
@end
let per = Person.init(name: "小明", sex: "男")
print(per.name)
print(per.sex)//输出:
//Optional("小明")
//男
Swift 中如何使用C++
在OC文件是直接可以使用C语言的,使用C++,只需要将.m文件后缀名改为.mm就可以使用C++的语法了。
在Swift中也是可以使用C语言的,具体使用Swift和C语言的混合使用
但是对与C++的使用相对就麻烦很多,一般采用OC对象包裹的形式去使用C++的对象。在Swift项目中OC头文件中是不能引入C++的,否则的会报file not found 的错误,我们需要在.mm文件中使用C++对象
在Objective-C中使用Swift
官方文档
相对与在Swift 中使用Objective-C来说,在Objective-C中使用Swift要复杂很多。
如何将Swift文件引入到OC项目中
第一次在OC项目中创建Swift文件时,xcode也是会提醒创建桥接文件的,这个文件的作用也是给Swift文件中调用OC使用的.
在OC文件中使用当前项目的Swift文件
我们可以在 Targets–>Build Settings–>Swift Compiler - General–>Objective-C Generated Interface Header Name 看到我们需要在OC中将引入Swift内容的头文件。这个文件默认是 **“项目名-Swift.h” ** ,这个头文件也可以改成我们自定义的名称。只需要在OC中#import这个头文件就可以了。这种方式是
#import "ProductModuleName-Swift.h"
在OC文件中使用当前其他Framework中的Swift文件
ProductModuleName-Swift.h和上面的一样,只需要在前面加上个项目名就可以使用其他framework中的swift文件
#import <ProductName/ProductModuleName-Swift.h>
在OC使用Swift需要注意什么
Objective-C 对象是基于运行时的,在运行调用时再决定实际调用的具体实现。而 Swift 为了追求性能,通常情况下是不会在运行时再来决定这些的。也就是说,Swift 类型的成员或者方法在编译时就已经决定,而运行时便不再需要经过一次查找。Objective-C 中所有类都继承自NSObject
,为了能在OC中调用 Swift 中的类,Swift也必须继承NSObject。
首先我们需要先了解@objc、@objcMembers和dynamic这三个关键字的含义
@objc Swift @objc 关键字文档
@objc
修饰符是用来暴露接口给 Objective-C 的运行时(类、协议、属性和方法等。@nonobjc
修饰符不暴露接给 Objective-C 的运行时,通常可以是使用了@objcMembers修饰了类,但是某些方法不想在OC中使用添加
@objc
修饰符并不意味着这个方法或者属性会采用 Objective-C 的方式变成动态派发,Swift 依然可能会将其优化为静态调用@objc
修饰符的隐式添加的情况覆重写一个@objc声明的计算属性或者方法
import Foundationclass Person: NSObject {@objc var name :String{return "小明"}@objc var sex:String = "男"@objc func demo(){} }class Student: Person {override var name: String{return ""}//Cannot override with a stored property 'sex'//子类不能重写父类的存储属性//override var sex: String = "男"override func demo() {} }
实现一个使用@objc修饰协议
@objc protocol MyProtocol {func myFun() }class Person: MyProtocol {func myFun() {} }
当属性声明为@IBAction或者@IBOutlet
当属性声明为@NSManaged
@objcMembers 修饰的类,它和它子类的属性方法扩展都会隐式的添加上@objc
@objcMembers class MyClass : NSObject {func foo() { } // implicitly @objcfunc bar() -> (Int, Int) // not @objc, because tuple returns// aren't representable in Objective-C }extension MyClass {func baz() { } // implicitly @objc }class MySubClass : MyClass {func wibble() { } // implicitly @objc }extension MySubClass {func wobble() { } // implicitly @objc }
下面的这些情况将不在隐式添加@objc (Swift4以后)
- 需要特别指明
dynamic
不再隐式添加@objc
class MyClass {dynamic func foo() { } // error: 'dynamic' method must be '@objc'@objc dynamic func bar() { } // okay }
- NSObject的子类将不再隐式添加@objc
class MyClass : NSObject {func foo() { } //在OC不能使用 }
即遵循 Swift API Design Guidelines 的代码将使用的Swift名称,这些名称通常会转换为非常差的Objective-C名称,从而违反了针对Objective-C Coding Guidelines for Cocoa.
class MyNumber : NSObject {init(_ int: Int) { }init(_ double: Double) { } // error: initializer 'init' with Objective-C selector 'init:' // conflicts with previous declaration with the same Objective-C selector }
class MyNumber : NSObject {@objc(initWithInteger:) init(_ int: Int) { }@objc(initWithDouble:) init(_ double: Double) { } }@objc(Student)// Only classes that inherit from NSObject can be declared @objc class Person: NSObject {}class Person: NSObject {@objc(age) var name = "" }
@objcMembers
@objcMembers只能用来修饰类。使用@objcMembers修饰的类,系统会在自动给这个类的所有方法添加@objc,暴露给OC。
dynamic (使用dynamic修饰的属性,在Swift4之后是不会自动添加上@objc的)
dynamic修饰的属性和方法是告诉编译器使用动态分发而不是静态分发,使用动态分发,您可以更好的与OC中runtime的一些特性(如CoreData,KVC/KVO)进行交互。
在Swift中使用KVO
class Person: NSObject {@objc dynamic var name = "" //@objc在Swift4之后必须要添加func demo() {addObserver(self, forKeyPath: #keyPath(Person.name), options: [.initial,.new], context: nil)}
}
Swift和Objective-C互相调用相关推荐
- swift 多线程GCD和延时调用
GCD 是一种非常方便的使用多线程的方式.通过使用 GCD,我们可以在确保尽量简单的语法的前提下进行灵活的多线程编程.在 "复杂必死" 的多线程编程中,保持简单就是避免错误的金科玉 ...
- Swift 函数的定义及调用
1.函数的基本概念 函数是一个独立的代码块,用来执行特定的任务.通过给函数一个名字来定义它的功能,并且在需要的时候,通过这个名字来"调用"函数执行它的任务 Swift 统一的函数语 ...
- iOS swift awakeFromNib方法未被调用
在swift中有两个awakeFromNib方法,一个类方法,一个对象方法,你写的可能是类方法,所以在xib中的视图加载完后未被调用 1.如下图,敲aw会提示两个awakeFromNib方法 2.敲出 ...
- swift和c语言互相调用教程
目录 前言 swift调用c语言的方法. 建立桥接文件 桥接文件中包含 c语言的 .h头文件 在c语言中调用swift的方法 在桥接桥接文件中声明 函数指针 swift中调用 demo下载点击我 前言 ...
- Swift之高德地图的调用
运用swift开发已有半年之久,最近闲来没事.学习了一点地图的知识,现在来与大家分享.直接上代码吧! <一>高德地图搜索功能 控制器 // // ViewController.swift ...
- swift 打包sdk_在封装SDK中Swift和OC混编之相互调用
oc和swift混编之相互调用.jpg 在非SDK中: 1.swift调用oc 步骤: 创建 工程名-Bridging-Header.h 放入oc的头文件,swift即可调用 在swift项目中或者在 ...
- swift 5.1和oc双语言 WechatOpenSDK (1.8.7.1)微信登录集成教程封装成支持swift和oc方法调用
目录 先看一下demo演示 安装pod 安装 到微信官网注册账户,并获取3个数据 添加关联域名 Associated Domains info.plist里面 添加 白名单 添加 URL Scheme ...
- Swift中文教程(十一) 方法
方法是关联到一个特定类型的函数.类.结构.枚举所有可以定义实例方法,封装特定任务和功能处理给定类型的一个实例.类.结构.枚举类型还可以定义方法,相关的类型本身.类型方法类似于objective – c ...
- ios .mm文件调用c语言函数报错,深入浅出 iOS 编译
前言 两年前曾经写过一篇关于编译的文章<iOS编译过程的原理和应用>,这篇文章介绍了iOS编译相关基础知识和简单应用,但也很有多问题都没有解释清楚: Clang和LLVM究竟是什么 源文件 ...
- Swift 代码调试核武-LLDB调试基础
原创Blog,转载请注明出处 http://blog.csdn.net/hello_hwc?viewmode=list 我的stackoverflow 前言:LLDB是个开源的调试器,与XCode绑定 ...
最新文章
- Intellij IDEA中开启Run Dashboard模式
- BZOJ 2143 飞飞侠(线段树优化建边 / 并查集优化最短路)【BZOJ修复工程】
- java线程同步以及对象锁和类锁解析(多线程synchronized关键字)
- QuickMock:基于Express的快速mock平台
- 罗辑思维在全链路压测方面的实践和工作笔记
- 建立Full Trust的Browser Application
- SSH框架搭建的时候遇到的问题
- 数据中心UPS电池故障引起火灾导致澳大利亚医院系统业务中断
- android studio 设置控制台字体大小
- mysql 新增从数据库_从零开始学 MySQL - 创建数据库并插入数据
- python 港股交易数据_GitHub - 116pythonZS/futuquant: 富途量化平台 API
- 解决tomcat的undeploy
- android 网易音乐sdk,Netease Music SDK 开发文档
- (二)探究本质,WebGIS前端地图显示之地图比例尺换算原理
- loadrunner录制时使用IE浏览器无响应问题
- 极路由添加静态路由表_如何将静态TCP / IP路由添加到Windows路由表
- 青龙面板+傻妞+JD(自用)
- 白兵机器人怎样连接_“玩具之家”的新宠——星战白兵冲锋队员机器人体验
- ASEMI整流二极管10A10参数,10A10压降,10A10作用
- Spring Security系列(10)- 微服务权限方案及Oauth2介绍
热门文章
- 疯狂Android讲义(一)——第四部分
- ICML/ICLR‘22 推荐系统论文梳理
- CTFHUB web-hate_php
- SM双生进程是如何通讯的?
- [附源码]java+ssm计算机毕业设计基于SSM的饭店餐饮管理系统09695(源码+程序+数据库+部署)
- struts filter
- CentOS7 Theia安装笔记
- [Java]还在用360压缩吗?自己写一个吧
- 内参矩阵、外参矩阵、旋转矩阵、平移矩阵、单应矩阵、本征矩阵、基础矩阵
- IntelliJ IDEA 2022.1 正式发布!新增依赖分析器,轻松解决依赖冲突问题。。