在一个项目中同时使用Swift和Objective-C代码混合编程的方法

Swift 与 Objective-C 的兼容能力使你可以在同一个工程中同时使用两种语言。你可以用这种叫做 mix and match 的特性来开发基于混合语言的应用,可以用 Swfit 的最新特性实现应用的一部分功能,并无缝地并入已有的 Objective-C 的代码中。

Mix and Match 概述

Objective-C 和 Swift 文件可以在一个工程中并存,不管这个工程原本是基于 Objective-C 还是 Swift。你可以直接往现有工程中简单地添加另一种语言的源文件。这种自然的工作流使得创建混合语言的应用或框架 target,与用单独一种语言时一样简单。

混合语言的工作流程只有一点点区别,这取决于你是在写应用还是写框架。下面描述了普通的用两种语言在一个 target 中导入模型的情况,后续章节会有更多细节。

在同个应用的 target 中导入

如果你在写混合语言的应用,可能需要用 Swift 代码访问 Objective-C 代码,或者反之。下面的流程描述了在非框架 target 中的应用。

将 Objective-C 导入 Swift

在一个应用的 target 中导入一些 Objective-C 文件供 Swift 代码使用时,你需要依赖与 Objective-C 的桥接头文件(bridging header)来暴露给 Swift。当你添加 Swift 文件到现有的 Objective-C 应用(或反之)时,Xcode 会自动创建这些头文件。

如果你同意,Xcode 会在源文件创建的同时生成头文件,并用 product 的模块名加上 -Bridging-Header.h 命名。关于 product 的模块名,详见 Naming Your Product Module。

你应该编辑这个头文件来对 Swift 暴露出 Objective-C 代码。

在同一 target 中将 Objective-C 代码导入到 Swift 中

1) 在 Objective-C 桥接头文件中,import 任何你想暴露给 Swift 的头文件,例如:

复制代码 代码如下:

// OBJECTIVE-C

#import "XYZCustomCell.h"
#import "XYZCustomView.h"
#import "XYZCustomViewController.h"

2) 确保在 Build Settings 中 Objective-C 桥接头文件的 build setting 是基于 Swfit 编译器,即 Code Generation 含有头文件的路径。这个路径必须是头文件自身的路径,而不是它所在的目录。

这个路径应该是你工程的相对路径,类似 Info.plist 在 Build Settings 中指定的路径。在大多数情况下,你不需要修改这个设置。

在这个桥接头文件中列出的所有 public 的 Objective-C 头文件都会对 Swift 可见。之后当前 target 的所有 Swift 文件都可以使用这些头文件中的方法,不需要任何 import 语句。用 Swift 语法使用这些 Objective-C 代码,就像使用系统自带的 Swift 类一样。

复制代码 代码如下:

// SWIFT

let myCell = XYZCustomCell()
myCell.subtitle = "A custom cell"

将 Swift 导入 Objective-C

向 Objective-C 中导入Swift 代码时,你依赖 Xcode 生成的头文件来向 Objective-C 暴露 Swift 代码。这是自动生成 Objective-C 头文件,它包含了你的 target 中所有 Swift 代码中定义的接口。可以把这个 Objective-C 头文件看作 Swift 代码的 umbrella header。它以 product 模块名加 -Swift.h 来命名。关于 product 的模块名,详见Naming Your Product Module。

你不需要做任何事情来生成这个头文件,只需要将它导入到你的 Objective-C 代码来使用它。注意这个头文件中的 Swift 接口包含了它所使用到的所有 Objective-C 类型。如果你在 Swift 代码中使用你自己的 Objective-C 类型,确保先将对应的 Objective-C 头文件导入到你的 Swift 代码中,然后才将 Swift 自动生成的头文件导入到 Objective-C .m 源文件中来访问 Swift 代码。

在同一 target 中将 Swift 代码导入到 Objective-C 中

在相同 target 的 Objective-C .m 源文件中,用下面的语法来导入Swift 代码:

复制代码 代码如下:

// OBJECTIVE-C
#import "ProductModuleName-Swift.h"

target 中任何 Swift 文件将会对 Objective-C .m 源文件可见,包括这个 import 语句。关于在 Objective-C 代码中使用 Swift 代码,详见 Using Swift from Objective-C

  导入到 Swift 导入到 Swift
Swift 代码 不需要import语句 #import
Objective-C 代码 不需要import语句;需要 Objective-C `umbrella头文件 #import "Header.h"

在同个 Framework 的 target 中导入

如果你在写一个混合语言的框架,可能会从 Swift 代码访问 Objective-C 代码,或者反之。

将 Objective-C 导入 Swift

要将一些 Objective-C 文件导入到同个框架 target 的 Swift 代码中去,你需要将这些文件导入到 Objective-C 的 umbrella header来供框架使用。

在同一 framework 中将 Objective-C 代码导入到 Swift 中

确保将框架 target 的 Build Settings > Packaging > Defines Module 设置为 Yes。然后在你的 umbrella header 头文件中导入你想暴露给 Swift 访问的 Objective-C 头文件,例如:

复制代码 代码如下:

// OBJECTIVE-C
#import <XYZ/XYZCustomCell.h>
#import <XYZ/XYZCustomView.h>
#import <XYZ/XYZCustomViewController.h>

Swift 将会看到所有你在 umbrella header 中公开暴露出来的头文件,框架 target 中的所有 Swift 文件都可以访问你 Objective-C 文件的内容,不需要任何 import 语句。

复制代码 代码如下:

// SWIFT
let myCell = XYZCustomCell()
myCell.subtitle = "A custom cell"

将 Swift 导入 Objective-C

要将一些 Swift 文件导入到同个框架的 target 的 Objective-C 代码去,你不需要导入任何东西到 umbrella header 文件,而是将 Xcode 为你的 Swift 代码自动生成的头文件导入到你的 Obj .m 源文件去,以便在 Objective-C 代码中访问 Swift 代码。

在同一 framework 中将 Swift 代码导入到 Objective-C 中

确保将框架 target 的 Build Settings > Packaging 中的 Defines Module 设置为 Yes。用下面的语法将 Swift 代码导入到同个框架 target 下的 Objective-C .m 源文件去。

复制代码 代码如下:

// OBJECTIVE-C
#import <ProductName/ProductModuleName-Swift.h>

这个 import 语句所包含的 Swift 文件都可以被同个框架 target 下的 Objective-C .m 源文件访问。关于在 Objective-C 代码中使用 Swift 代码,详见 Using Swift from Objective-C

  导入到 Swift 导入到 Swift
Swift 代码 不需要import语句 #import
Objective-C 代码 不需要import语句;需要 Objective-C `umbrella头文件 #import "Header.h"

在 Objective-C 中使用 Swift

当你将 Swift 代码导入 Objective-C 文件之后,用普通的 Objective-C 语法使用 Swift 类。

复制代码 代码如下:

// OBJECTIVE-C

MySwiftClass *swiftObject = [[MySwiftClass alloc] init];
[swiftObject swiftMethod];

Swift 的类或协议必须用 @Objective-C attribute 来标记,以便在 Objective-C 中可访问。这个 attribute 告诉编译器这个 Swift 代码可以从 Objective-C 代码中访问。如果你的 Swift 类是 Objective-C 类的子类,编译器会自动为你添加 @Objective-C attribute。详见 Swift Type Compatibility

你可以访问 Swift 类或协议中用 @Objective-C attribute 标记过东西,只要它和 Objective-C 兼容。不包括一下这些 Swift 独有的特性:

•Generics - 范型
•Tuples - 元组
•Enumerations defined in Swift - Swift 中定义的枚举
•Structures defined in Swift - Swift 中定义的结构体
•Top-level functions defined in Swift - Swift Swift 中定义的顶层函数
•Global variables defined in Swift - Swift 中定义的全局变量
•Typealiases defined in Swift - Swift 中定义的类型别名
•Swift-style variadics - Swift风格可变参数
•Nested types - 嵌套类型
•Curried functions - 柯里化后的函数

例如带有范型类型作为参数,或者返回元组的方法不能在 Objective-C 中使用。

为了避免循环引用,不要将 Swift 代码导入到 Objective-C 头文件中。但是你可以在 Objective-C 头文件中前向声明(forward declare)一个 Swift 类来使用它,然而,注意不能在 Objective-C 中继承一个 Swift 类。

在 Objective-C 头文件中引用 Swift 类

这样前向声明 Swift 类:

复制代码 代码如下:

// OBJECTIVE-C
// MyObjective-CClass.h

@class MySwiftClass;

@interface MyObjective-CClass : NSObject
- (MySwiftClass *)returnSwiftObject;
/* ... */
@end

Product 模块命名

Xcode 为 Swift 代码生成的头文件的名称,以及 Xcode 创建的 Objective-C 桥接头文件名称,都是从你的 product 模块名生成的。默认你的 product 模块名和 product 名一样。然而,如果你的 product 名有特殊字符(nonalphanumeric,非数字、字母的字符),例如点号,那么它们会被下划线(_)替换之后作为你的 product 模块名。如果 product 名以数字开头,那么第一个数字会用下划线替换掉。

你可以给 product 模块名提供一个自定义的名称,Xcode 会用这个名称来命名桥接的和自动生成的头文件。你只需要在修改在build setting 中的 Product Module Name 即可。

问题解决提示

•把 Swift 和 Objective-C 文件看作相同的代码集合,并注意命名冲突;
•如果你用框架,确保 Build Setting > Pakaging > Defines Module 设置为 Yes;
•如果你使用 Objective-C 桥接头文件,确保在 Build Settings 中 Objective-C 桥接头文件的 build setting 是基于 Swfit 编译器,即 Code Generation 含有头文件的路径。这个路径必须是头文件自身的路径,而不是它所在的目录;
•Xcode 使用你的 product 模块名,而不是 target 名来命名 Objective-C 桥接头文件和为 Swift 自动生成的头文件。详见 Naming Your Product Module;
•为了在 Objective-C 中可用, Swift 类必须是 Objective-C 类的子类,或者用 @Objective-C 标记;
•当你将 Swift 导入到 Objective-C 中时,记住 Objective-C 不会将 Swift 独有的特性翻译成 Objective-C 对应的特性。详见列表Using Swift from Objective-C;
•如果你在 Swift 代码中使用你自己的 Objective-C 类型,确保先将对应的 Objective-C 头文件导入到你的 Swift 代码中,然后才将 Swift 自动生成的头文件 import 到 Objective-C .m 源文件中来访问 Swift 代码。

时间: 2014-07-19

swift中的正则表达式小结

作为一门先进的编程语言,Swift 可以说吸收了众多其他先进语言的优点,但是有一点却是让人略微失望的,就是 Swift 至今为止并没有在语言层面上支持正则表达式. 正则表达式的用处: 判断给定的字符串是否符合某一种规则(专门用于操作字符串) - 电话号码,电子邮箱,URL... - 可以直接百度别人写好的正则 - 别人真的写好了,而且测试过了,我们可以直接用 - 要写出没有漏洞正则判断,需要大量的测试,通常最终结果非常负责 过滤筛选字符串,网络爬虫 替换文字,QQ聊天,图文混排 语法规则 使用过

Swift的74个常用内置函数介绍

Swift包含了74个内置函数,但在 The Swift Programming Langage 一书中只介绍了其中的7个,其它的都没有在文档中体现. 这篇文章列举出了所有的Swift库函数.文中所谓的 内置函数 是指无需引入任何模块(比如说Fundation等)即可以直接使用的函数. 下面先来看看7个在文档中提到的库函数: 下面列出一些很实用,但未在文档中体现的库函数: 复制代码 代码如下: //断言,参数如果为`true`则继续,否则抛出异常 //assert mentioned on pa

Swift中的可变参数函数介绍

可变参数函数指的是可以接受任意多个参数的函数,我们最熟悉的可能就是 NSString 的 -stringWithFormat:方法了.在 Objective-C 中,我们使用这个方法生成字符串的写法是这样的: 复制代码 代码如下: NSString *name = @"Tom"; NSDate *date = [NSDate date]; NSString *string = [NSString stringWithFormat:                 @"Hell

Swift网络请求库Alamofire使用详解

前言 Alamofire是一个使用Swift开发的网络请求库,其开发团队是AFNetworking的原团队.它语法简洁,采用链式编程的思想,使用起来是相当的舒服.本质是基于NSURLSession进行封装.接下开我们就进入实战,开始学习Alamofire的使用. GET请求 常用的get请求示例以及请求结果 Alamofire.request("https://httpbin.org/get", method: .get, parameters: nil, encoding: URLE

android 网络请求库volley方法详解

使用volley进行网络请求:需先将volley包导入androidstudio中 File下的Project Structrue,点加号导包 volley网络请求步骤: 1. 创建请求队列       RequestQueue queue = Volley.newRequestQueue(this); 2.创建请求对象(3种) StringRequest request = new StringRequest("请求方法","请求的网络地址","成功的网

微信小程序之网络请求简单封装实例详解

微信小程序之网络请求简单封装实例详解 在微信小程序中实现网络请求相对于Android来说感觉简单很多,我们只需要使用其提供的API就可以解决网络请求问题. 普通HTTPS请求(wx.request) 上传文件(wx.uploadFile) 下载文件(wx.downloadFile) WebSocket通信(wx.connectSocket) 为了数据安全,微信小程序网络请求只支持https,当然各个参数的含义就不在细说,不熟悉的话可以:可以去阅读官方文档的网络请求api,当我们使用request

Android 网络请求框架Volley实例详解

Android 网络请求框架Volley实例详解 首先上效果图 Logcat日志信息on Reponse Volley特别适合数据量不大但是通信频繁的场景,像文件上传下载不适合! 首先第一步 用到的RequetQueue RequestQueue.Java RequestQueue请求队列首先得先说一下,ReuqestQueue是如何对请求进行管理的...RequestQueue是对所有的请求进行保存...然后通过自身的start()方法开启一个CacheDispatcher线程用于缓存调度,开

IOS网络请求之NSURLSession使用详解

前言: 无论是Android还是ios都离不开与服务器交互,这就必须用到网络请求,记得在2013年做iOS的时候那时候用的ASIHTTPRequest框架,现在重新捡起iOS的时候ASIHTTPRequest已经停止维护,大家都在用AFNetWorking作为首选网络请求框架,之前的ASIHTTPRequest是基于NSURLConnection类实现的,早期的AFNetWorking也是基于NSURLConnection实现,后来iOS9 之后已经放弃了NSURLConnection,开始使用

iOS中多网络请求的线程安全详解

前言 在iOS 网络编程有一种常见的场景是:我们需要并行处理二个请求并且在都成功后才能进行下一步处理.下面是部分常见的处理方式,但是在使用过程中也很容易出错: DispatchGroup:通过 GCD 机制将多个请求放到一个组内,然后通过 DispatchGroup.wait() 和 DispatchGroup.notify() 进行成功后的处理. OperationQueue:为每一个请求实例化一个 Operation 对象,然后将这些对象添加到 OperationQueue ,并且根据它们之

Android GZip的使用-开发中网络请求的压缩实例详解

Android  GZip: gzip是GNUzip的缩写,它是一个GNU自由软件的文件压缩程序. HTTP协议上的GZIP编码是一种用来改进WEB应用程序性能的技术.一般服务器中都安装有这个功能模块的,服务器端不需做改动. 当浏览器支持gzip 格式的时候, 服务器端会传输gzip格式的数据. 从Http 技术细节上讲,就是 http request 头中 有 "Accept-Encoding", "gzip" ,response 中就有返回头Content-En

python中数据爬虫requests库使用方法详解

一.什么是Requests Requests 是Python语编写,基于urllib,采Apache2 Licensed开源协议的 HTTP 库.它urllib 更加方便,可以节约我们大量的工作,完全满足HTTP测试需求. 一句话--requests是python实现的简单易用的HTTP库 二.安装Requests库 进入命令行win+R执行 命令:pip install requests 项目导入:import requests 三.各种请求方式 直接上代码,不明白可以查看我的urllib的基

Python即时网络爬虫项目启动说明详解

作为酷爱编程的老程序员,实在按耐不下这个冲动,Python真的是太火了,不断撩拨我的心. 我是对Python存有戒备之心的,想当年我基于Drupal做的系统,使用php语言,当语言升级了,推翻了老版本很多东西,不得不花费很多时间和精力去移植和升级,至今还有一些隐藏在某处的代码埋着雷.我估计Python也避免不了这个问题(其实这种声音已经不少,比如Python 3 正在毁灭 Python). 但是,我还是启动了这个Python即时网络爬虫项目.我用C++.Java和Javascript编写爬虫相关

Python 中Pickle库的使用详解

在"通过简单示例来理解什么是机器学习"这篇文章里提到了pickle库的使用,本文来做进一步的阐述. 那么为什么需要序列化和反序列化这一操作呢? 1.便于存储.序列化过程将文本信息转变为二进制数据流.这样就信息就容易存储在硬盘之中,当需要读取文件的时候,从硬盘中读取数据,然后再将其反序列化便可以得到原始的数据.在Python程序运行中得到了一些字符串.列表.字典等数据,想要长久的保存下来,方便以后使用,而不是简单的放入内存中关机断电就丢失数据.python模块大全中的Pickle模块就派