热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

swift和OC混编的一些tips

前言Objective-C代码重写成swift可能性不大,往后功能用swift写几乎没有人愿意在收益甚微的情况下把Objective-C代码重写一次,因为重写意味着大量的研发资源和
前言
  • Objective-C 代码重写成 swift 可能性不大,往后功能用 swift 写

几乎没有人愿意在收益甚微的情况下把 Objective-C 代码重写一次,因为重写意味着大量的研发资源和测试资源的消耗,而这基本不会产生实际意义上的产品收益。另外 Apple 在 Swift 和 Objective-C 的桥接上做了相当多的努力,大部分情况下,我们都可以不太费力的在 Swift 中复用 Objective-C 代码。

所以大部分公司的策略都会是新功能用 Swift 语言实现,旧功能先维持现状,等到产品变动或是架构变动的时候再使用 Swift 语言实现,这也是猿题库所采用的策略。所以我想短时间内不太可能完全迁移到 Swift 吧。如果非要说一个时间的话,我推测大约一年之后大部分业务应该会迁移到 Swift,而整个项目彻底迁移恐怕就需要两到三年以上了。

  • swift 目前不是很稳定,以OC 语法为基准,避免使用 Swift 语言的特性

从 Objective-C 迁移到 Swift 代表着在很长一段时间内都是处于混编的状态,这里我认为最重要的经验是一定要有一个迁移的规范和指南来约束开发团队哪些部分需要迁移 Swift 而哪些部分不要,接口应该如何设计才能兼顾混编调用。举个例子,由于 Swift 调用 Objective-C 是方便的可靠的,反之则有许多的限制,所以设计接口的时候,需要考虑这个模块会不会被 Objective-C 调用,如果是的话,应该避免使用 Swift 语言的特性,又或是制定一套规则,来 Swift 语言的接口如何转成 Objective-C 兼容的接口。

  • 使用 swift 是一个过渡,熟悉 swift 语法的过程

重上面的总结可以看出,由于 swift 语法还没有稳定,项目中使用 swift也应避免 swift 新特性;本质是 OC 代码转 swift;但是我们可以学习 swift 语法,将来 swift 稳定后更好的上手;

混编注意事项

@objc

在 Swift 代码中,使用@objc修饰后的类型,可以直接供 Objective-C 调用。可以使用@objc修饰的类型包括:

  • 未嵌套的类
  • 协议
  • 非泛型枚举(仅限于原始值为整形的类型)
  • 类和协议中的属性和方法
  • 构造器和析构器
  • 下标

每周 Swift 社区问答:@objc

对象方法类方法

与类方法比较,对象方法需要在前面加了一个class
The Swift Programming Language (Swift 3.0.1)-Methods

swift中是不能使用宏定义语法的,但是因为命名空间的缘故,我们可以给我们的项目添加一个空的Const.swift文件,在其中,我们将原本oc中不需要接受参数的宏,定义成let常量,将需要接受参数的宏定义成函数即可,由于我们的整个项目共享命名空间,我们就可以在项目内的任何地方直接使用Const.swift中定义的这些公共的常量和函数

1.没有参数的宏

//oc中的宏定义
#define kIOS7 [UIDevice currentDevice].systemVersion.doubleValue>=7.0 ? 1 :0
#define kIOS8 [UIDevice currentDevice].systemVersion.doubleValue>=8.0 ? 1 :0
#define kScreenHeight [UIScreen mainScreen].bounds.size.height
#define kScreenWidth [UIScreen mainScreen].bounds.size.width
//转换成swift的写法
let kIOS7 = (UIDevice().systemVersion as NSString).doubleValue >= 7.0 ? 1 :0
let kIOS8 = (UIDevice().systemVersion as NSString).doubleValue >= 8.0 ? 1 :0
let kScreenHeight = UIScreen.main.bounds.size.height
let kScreenWidth = UIScreen.main.bounds.size.width

2、接收参数的宏

//oc写法
#define RGBCOLOR(r,g,b) [UIColor colorWithRed:(r)/255.0 green:(g)/255.0 blue:(b)/255.0 alpha:1]
//swift中的写法
func RGBCOLOR(r:CGFloat,_ g:CGFloat,_ b:CGFloat) -> UIColor
{
return UIColor(red: (r)/255.0, green: (g)/255.0, blue: (b)/255.0, alpha: 1.0)
}

在 swift 中导入 OC 宏文件是没有用的,因为不能识别;例如kScreenWidth只能识别

let kScreenWidth = UIScreen.main.bounds.size.width

预编译命令

由于Swift没有预处理,正如Apple文档中所说:The Swift compiler does not include a preprocessor.
对于C或者OC中用来定义常量的宏,在Swift中可以使用全局的常量来代替。
Swift是根据构建配置来进行条件编译的。在需要区分开发还是发布版本的时候,OC这样做

#ifdef DEBUG
#else
#endif

但是在swift中没有DEBUG这个宏,如果要实现相同的需求

《swift 和 OC 混编的一些 tips》 设置预编译命令

预编译

在target下 Build Settings 搜索 Other [Swift](http://lib.csdn.net/base/swift) Flags
设置Debug 添加 -D DEBUG,注意不要好Release一起添加
使用方式和oc下一样
#if ABC // 判断是否在[测试]环境下
// TODO
#else
// TODO
#endif

OC->Swift advanced tips

swift 中使用 OC类

Swift调用Objective-C文件比较简单。当在Swift工程中新建Objective-C文件或者在Objective-C工程中新建Swift文件时,Xcode会自动提示你是否创建bridging header桥接头文件,点击创建后Xcode会自动为你创建一个桥接头文件。如图1-1、1-2所示,在基于Swift的SwiftProject工程中创建一个OCViewController时,Xcode会自动创建一个名为SwiftProject-Bridging-Header.h桥接头文件。

《swift 和 OC 混编的一些 tips》 Swift工程中自动提示是否创建桥接头文件

注意:可能方法名 swift 会帮你改变些

OC 中使用 swift 类

Xcode会自动为Project生成头文件以便在Objective-C中调用。在Objective-C类中调用Swift,只需要#import “productModuleName-Swift.h”即可调用,Xcode提供的头文件以Swift代码的模块名加上-Swift.h为命名。在这个头文件中,将包含Swift提供给Objective-C的所有接口、Appdelegate及自动生成的一些宏定义,如图1-5所示。注意productModuleName-Swift.h在Xcode中是无法搜索查看的,只能从import中点击进去查看。

《swift 和 OC 混编的一些 tips》 查看 swift 文件的. h 头文件

枚举

在 OC 中的枚举建议使用 typedef 这种格式, swift 会自动帮忙转换,其他的枚举格式转换不了

typedef NS_ENUM(NSInteger, QDMenuItemType) {
QDMenuItemTypePlaceHolder = 0,
QDMenuItemTypeCredit = 1,
QDMenuItemTypeOrder = 2,
QDMenuItemTypeGiftCard = 3,
QDMenuItemTypeFocus = 4,
QDMenuItemTypeAddress = 5,
QDMenuItemTypeCooperation = 6,
QDMenuItemTypeWX = 7,
QDMenuItemTypeWXLine = 8,
QDMenuItemTypeQQ = 9,
};
override func handleMenuItemClick(_ type: QDMenuItemType) {

var index = 0;

switch type {
case QDMenuItemType.WX:
index = 0;
break;
case QDMenuItemType.wxLine:
index = 1;
break;
case QDMenuItemType.QQ:
index = 2;
break;
default:

break;
}

let urlStr = "https://htest.qianduan.com/app/download";
let cOntentMsg= "预约投资轻松理财,随时随地享收益,想赚请戳我";
let projectName = "投资达人都该拥有!";

self.share(with: index, url: urlStr, contentMsg: contentMsg, title: projectName, thumImage: nil);
}

How to use Objective-C enum in Swift [duplicate]

懒加载

它本质在siwft中确实是一个闭包,执行顺序是这样的,如果这个lazy修饰的变量没值,就会执行闭包中的东西,不是每次都执行(本人补充:这也就是为什么在Swift中的懒加载没有oc中判断。if(xx==nil){初始化xx}的代码段)。

懒加载有两种调用方式:
1.带有Lazy关键字修饰的闭包方式,这种只有在使用的时候才会调用,Lazy是延迟调用关键字.
2.只使用闭包的方式,这种方式没有延迟调用的特性,在持有它的对象初始化的时候就会调用,就像上面的代码label2.

lazy var label1: UILabel = {//CGRectMake(30, 30, 200, 50)
let label1 = UILabel.init(frame:CGRect(x: 30, y: 30, width: 200, height: 50))
label1.text = "lazy方式懒加载lable1"
label1.textColor = UIColor.white
label1.backgroundColor = UIColor.cyan

return label1
}() private var label2 : UILabel = {
let label2 = UILabel.init(frame:CGRect(x: 30, y: 30, width: 200, height: 50))
label2.text = "闭包方式懒加载lable1"
label2.textColor = UIColor.white
label2.backgroundColor = UIColor.red

return label2
}()

optional 关键字

一般是使用系统推荐的,没有自己强行去设置;不是很熟建议使用系统的;

extension 的用法

扩展和 Objective-C 中的分类(categories)类似。(不过与Objective-C不同的是,Swift 的扩展没有名字。)

Swift 中的扩展可以:

  • 添加计算型属性和计算静态属性
  • 定义实例方法和类型方法
  • 提供新的构造器
  • 定义下标
  • 定义和使用新的嵌套类型
  • 使一个已有类型符合某个协议

注意:
如果你定义了一个扩展向一个已有类型添加新功能,那么这个新功能对该类型的所有已有实例中都是可用的,即使它们是在你的这个扩展的前面定义的。

https://numbbbbb.gitbooks.io/-the-swift-programming-language-/content/chapter2/20_Extensions.html

delegate notification closure

delegate

  • weak引用的问题

想要在 Swift 中使用 weak delegate,我们就需要将 protocol 限制在 class 内。一种做法是将 protocol 声明为 Objective-C 的,这可以通过在 protocol 前面加上 @objc 关键字来达到,Objective-C 的 protocol 都只有类能实现,因此使用 weak 来修饰就合理了:

@objc protocol MyClassDelegate {
func method()
}

另一种可能更好的办法是在 protocol 声明的名字后面加上 class,这可以为编译器显式地指明这个 protocol 只能由 class 来实现。

protocol MyClassDelegate: class {
func method()
}

相比起添加 @objc,后一种方法更能表现出问题的实质,同时也避免了过多的不必要的 Objective-C 兼容,可以说是一种更好的解决方式。

DELEGATE

@OBJC 和 DYNAMIC

  • option关键字

默认是 require,如果想可选 前面加option

public protocol UITableViewDataSource : NSObjectProtocol { @available(iOS 2.0, *)
public func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int @available(iOS 2.0, *)
public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell @available(iOS 2.0, *)
optional public func numberOfSections(in tableView: UITableView) -> Int // Default is 1 if not implemented
}

  • responseToSeletor

可选类型(option),不用去判断

Swift 中如何实现Object-C的respondsToSelector

notification

notification 的用法 swift与 OC 保持一致,写法上有些不一样NotificationCenter issue on Swift 3

通知名:

  • OC中为 NSString 类型
  • swift变成Notification.Name结构体类型

swift中通知的推荐写法

// Definition:
extension Notification.Name {
static let yourCustomNotificatiOnName= Notification.Name("yourCustomNotificationName")
}
// Usage:
NotificationCenter.default.post(name: .yourCustomNotificationName, object: nil)

closure(闭包)

闭包和OC中的block非常相似

  • OC中的block是匿名的函数
  • Swift中的闭包是一个特殊的函数
  • block和闭包都经常用于回调


let request = QDAppGlobalConfigsRequestDto()
QDIndexService().request(request, sucessBlock: { (response) in

if let result = response as? QDAppGlobalConfigsResponse{
print(result)
}

}, fail: { (error) in

QDShowErrorTool.showCommonErrorMsg(error, allowShow: true);

})

循环引用:

  • 使用weak修饰变量, 打破强引用, 因为使用weak修饰的变量有一次变成nil的机会

weak var weakSelf = self

  • 使用[weak self] 修饰闭包原理跟__weak类似, 这样在闭包中使用self, 就是弱引用

let closure = { [weak self] in
self?.doSomething() //记住,所有的weak变量都是可选类型。
}

  • 使用[unowned self] 修饰闭包, 跟__unsafe_unretained类似, 不安全

closure = { [unowned self] in
self.string = "Hello, World!"
}

解析Swift中闭包的循环引用

https://numbbbbb.gitbooks.io/-the-swift-programming-language-/content/chapter2/21_Protocols.html

命名空间

swift 和 OC的 class 名不能一样,否者会重复命名的错误

/Users/chenbowen/Library/Developer/Xcode/DerivedData/OC2SwiftDemo-bhnddbvgrdbyriarpwmbreemuhdm/Build/Intermediates/OC2SwiftDemo.build/Debug-iphonesimulator/OC2SwiftDemo.build/DerivedSources/OC2SwiftDemo-Swift.h:136:1: Duplicate interface definition for class 'EnumTestViewController'

OC 中获取不能直接通过 swift类名来获取类,需要加上工程名;否者会报错

NSString *classStr = self.listArr[indexPath.row];
Class vcClass = NSClassFromString(classStr);//命名空间的问题
swift 中的类

Application tried to push a nil view controller on target .

swift 可以允许同名的类出现,但是需要需要放在不同的空间中,具体可以可以王巍文档命名空间

swift 和 OC 的全局变量

  • swift中使用 OC 全局变量,需要 import 头文件就可以

  • OC 想使用 swift 定义的全局变量;需要swift 提供一个方法
    Swift globals in objective c

  • swift 中定义全局变量,放在类外面就可以;swift的全局变量不能重名,如果两个重名都会报错

模拟器可以运行,真机运行报错

真机调试APP时报dyld: Library not loaded: @rpath/XXX等错误

XCode真机调试APP时报dyld: Library not loaded: @rpath/XXX等错误

参考文档

猿题库从 Objective-C 到 Swift 的迁移
每周 Swift 社区问答:@objc
The Swift Programming Language (Swift 3.0.1)-Methods
OC->Swift advanced tips(1)
How to use Objective-C enum in Swift [duplicate]
DELEGATE
@OBJC 和 DYNAMIC
Swift 中如何实现Object-C的respondsToSelector
NotificationCenter issue on Swift 3
解析Swift中闭包的循环引用
命名空间
Swift globals in objective c
XCode真机调试APP时报dyld: Library not loaded: @rpath/XXX等错误


推荐阅读
  • 生成式对抗网络模型综述摘要生成式对抗网络模型(GAN)是基于深度学习的一种强大的生成模型,可以应用于计算机视觉、自然语言处理、半监督学习等重要领域。生成式对抗网络 ... [详细]
  • 在Android开发中,使用Picasso库可以实现对网络图片的等比例缩放。本文介绍了使用Picasso库进行图片缩放的方法,并提供了具体的代码实现。通过获取图片的宽高,计算目标宽度和高度,并创建新图实现等比例缩放。 ... [详细]
  • 本文介绍了C#中生成随机数的三种方法,并分析了其中存在的问题。首先介绍了使用Random类生成随机数的默认方法,但在高并发情况下可能会出现重复的情况。接着通过循环生成了一系列随机数,进一步突显了这个问题。文章指出,随机数生成在任何编程语言中都是必备的功能,但Random类生成的随机数并不可靠。最后,提出了需要寻找其他可靠的随机数生成方法的建议。 ... [详细]
  • 本文介绍了PhysioNet网站提供的生理信号处理工具箱WFDB Toolbox for Matlab的安装和使用方法。通过下载并添加到Matlab路径中或直接在Matlab中输入相关内容,即可完成安装。该工具箱提供了一系列函数,可以方便地处理生理信号数据。详细的安装和使用方法可以参考本文内容。 ... [详细]
  • 自动轮播,反转播放的ViewPagerAdapter的使用方法和效果展示
    本文介绍了如何使用自动轮播、反转播放的ViewPagerAdapter,并展示了其效果。该ViewPagerAdapter支持无限循环、触摸暂停、切换缩放等功能。同时提供了使用GIF.gif的示例和github地址。通过LoopFragmentPagerAdapter类的getActualCount、getActualItem和getActualPagerTitle方法可以实现自定义的循环效果和标题展示。 ... [详细]
  • 开发笔记:计网局域网:NAT 是如何工作的?
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了计网-局域网:NAT是如何工作的?相关的知识,希望对你有一定的参考价值。 ... [详细]
  • flowable工作流 流程变量_信也科技工作流平台的技术实践
    1背景随着公司业务发展及内部业务流程诉求的增长,目前信息化系统不能够很好满足期望,主要体现如下:目前OA流程引擎无法满足企业特定业务流程需求,且移动端体 ... [详细]
  • 本文介绍了Android 7的学习笔记总结,包括最新的移动架构视频、大厂安卓面试真题和项目实战源码讲义。同时还分享了开源的完整内容,并提醒读者在使用FileProvider适配时要注意不同模块的AndroidManfiest.xml中配置的xml文件名必须不同,否则会出现问题。 ... [详细]
  • Java学习笔记之面向对象编程(OOP)
    本文介绍了Java学习笔记中的面向对象编程(OOP)内容,包括OOP的三大特性(封装、继承、多态)和五大原则(单一职责原则、开放封闭原则、里式替换原则、依赖倒置原则)。通过学习OOP,可以提高代码复用性、拓展性和安全性。 ... [详细]
  • 深入理解Kafka服务端请求队列中请求的处理
    本文深入分析了Kafka服务端请求队列中请求的处理过程,详细介绍了请求的封装和放入请求队列的过程,以及处理请求的线程池的创建和容量设置。通过场景分析、图示说明和源码分析,帮助读者更好地理解Kafka服务端的工作原理。 ... [详细]
  • IjustinheritedsomewebpageswhichusesMooTools.IneverusedMooTools.NowIneedtoaddsomef ... [详细]
  • 集成电路企业在进行跨隔离网数据交换时面临着安全性问题,传统的数据交换方式存在安全性堪忧、效率低下等问题。本文以《Ftrans跨网文件安全交换系统》为例,介绍了如何通过丰富的审批流程来满足企业的合规要求,保障数据交换的安全性。 ... [详细]
  • 本文介绍了一个视频转换软件MyVideoConverter,该软件支持将mpg转换成swf格式,支持多种格式的转换,转换速度快,还能转换成3GP格式,同时具有音频分离提取功能。欢迎使用MyVideoConverter进行视频转换和音频提取。 ... [详细]
  • ①页面初始化----------收到客户端的请求,产生相应页面的Page对象,通过Page_Init事件进行page对象及其控件的初始化.②加载视图状态-------ViewSta ... [详细]
  • 作用域链迷惑性代码vara100;functiontest(){console.log(a);}functiontestFun(){vara200;test();}不假思索的想到出 ... [详细]
author-avatar
nikechen
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有