强制解包看 Swift 的设计
不知道大家有没有发现,在一个 Objective-C 和 Swift 混编的 App 中,当把一个 OC 中的参数转到 Swift 时,Swift 会自动把这个变量进行强制解包。举个例子,我在 OC 中定义这样一个变量:
@property (nonatomic, copy) NSString *foo;
它转成 Swift 就变成了这样:
var foo: String!
这样看上去合情合理。Swift 中有 String? 和 String! 两种形式,但 OC 中没有 NSString? 和 NSString! ,当 Swift 无法区分 OC 中的变量是不是 nil 的时候,一律强行转化为非空参数。这样设计体现了 Swift 强安全性语言的特性。
但是这时候问题来了。我们回到上文中的例子,假如 OC 中对 foo的使用如下:
@property (nonatomic, copy) NSString *foo;- (void)secretFunc { // 一些诡异复杂的操作... self.foo = nil; }
然后我们在 Swift 中这样调用:
func init() {objectiveCObject.secretFunc()
}func calcLen() -> Int {
return objectiveCObject.foo.characters.count
}
上面这段 Swift 代码执行到calcLen()时会崩溃,原因是foo在init()中已经被设成了 nil,而foo在 Swift 中是 foo!。也就是说,因为 Swift 对 OC 变量的强转,导致了程序的崩溃。这是一个很容易忽略的问题,因为强转的时候,Xcode 不会给出任何的警告、报错或是提醒。而我们作为开发者,很容易忽略这样的错误,导致 runtime 的时候直接崩溃。
针对这种情况,我们来讨论下面三个问题。
Q: 为什么 Swift 要将 OC 中的变量如foo转为foo!而不是foo?
这是一个有争议的话题。我个人认为强制解包的方式会督促开发者考虑变量是否为 nil 的问题。在 OC 时代,声明变量一般不会考虑是否为空的问题;而在 Swift 时代,因为其是一门强安全性的语言,在变量定义时,必须确定变量是否为空。一般定义为非空有两种以下形式:
// force unwrapping
var foo = "Hello"
// implicitly unwrapping
var foo: String!
前者根据初始值强制解包,定义 foo 为非空变量;后者则直接申明 foo 为非空变量。
无论哪种情况,开发者会从一开始就思考处理 nil 时的情况,并在后续开发中一直注意。所以从foo转化为foo!,你就会思考 OC 中代码是否也要处理
nil 的情况;而如果转化为foo?,nil 也无所谓,而实际可能并不是这样,nil 的特殊情况考虑会一直忽略,开发中的隐患一直存在,同时也不符合 Swift 强安全性的设计思路。
Q: 我就想让 OC 中的变量从foo转化到 Swift 中变成foo?,有没有办法
请这样在 OC 中定义变量:
// foo -> foo?
@property (nullable, nonatomic, copy) NSString *foo;
// bar -> bar!
@property (nonnull, nonatomic, copy) NSString *bar;
// qux -> qux!
@property (nonatomic, copy) NSString *qux;
这种事先声明是否为 null 的定义方法,是不是很像 Swift 中的 optional 机制?然而 OC 时代我们几乎不会去管变量是否为 nullable 这件事,由此我们可以体会 OC 和 Swift 在语言设计思路上的差异。
其实nullable和nonnull是 Swift 出来之后才引入 OC 的。所以一开始,OC 中的变量默认都是nullable,转变到 Swift 中,应该就是?。但是这样转化代价太大,我们所有变量都要在 Swift 中用if else或者guard来解包。所以为了写起来方便,Swift 干脆直接强转,故而现在这个机制也是一个历史遗留问题。
Q: Swift 如此这般导致混编 App 崩溃,没有提示的情况下程序员必须细细检查 nil 导致的 bug,这样设计强制解包的代价是否有点大?
这个 bug 在混编 App 中很容易出现,没有警告确实带来很大困扰。实际上这个问题早就在苹果的开发者论坛上被提出,Swift 组自己也开了个 ticket 要修,可惜最后不了了之。Github 上有人开发出了第三方的工具来解决这个问题。
我个人觉得这个问题苹果不重视的原因在于 Swift 和 OC 混编只是一个暂时的局面。Swift 取代 OC 是一个时间问题,所以解决混编中的问题都显得没有多大意义,在苹果内部也一直是低优先级。毕竟现在所有精力应该放在 Swift 上,随着时间的推移和 OC 的淡出,这个问题也将微不足道。
转载于:https://blog.51cto.com/jsw55667/1928853
强制解包看 Swift 的设计相关推荐
- Swift基础(六)解包
// 解包(if let语句和 guard语句) // 1. if let 可选类型在每次访问的时候都会提取并检测他的值是否存在,但有时候根据程序结构可以推断可选量在首次赋值后必然存在 ...
- python解包什么意思_Python 解包骚操作,看这篇文章
导读:本文总结了 Python 解包操作的方方面面,文章略长,看本文前,首先确保身边有多个不同版本 Python 解释器的电脑(公众号回复 conda ,了解如何安装多个环境),以便随时验证代码.看完 ...
- Python的解包知识
在Python中的代码中经常会见到 *args 和 **kwargs.args 是 arguments 的缩写,*args表示位置参数:kwargs 是 keyword arguments 的缩写 ...
- 一文详解JavaBean 看这篇就够了
一文详解JavaBean 看这篇就够了 JavaBean的历史渊源 JavaBean的定义(通俗版) JavaBean应用 < jsp:useBean > < jsp:getProp ...
- linux 如何打包分区文件,Linux基础------文件打包解包---tar命令,文件压缩解压---命令gzip,vim编辑器创建和编辑正文件,磁盘分区/格式化,软/硬链接...
作业一: 1)将用户信息数据库文件和组信息数据库文件纵向合并为一个文件/1.txt(覆盖) cat /etc/passwd /etc/group > /1.txt 2)将用户信息数据库文件和用户 ...
- python *args和**kwargs以及序列解包
DAY 8. *args和**kwargs *args:多值元组,**kwargs多值字典,他们是python函数传参时两个特殊的参数,args和kwargs并不是强制的,但习惯使用这两个,如果在函数 ...
- 网络粘包解包问题杂谈
1.如何解决粘包问题? 在设计网络协议时,可能会存在粘包.丢包或者包乱序问题,但TCP协议时可靠性协议,大多数情况不存在丢包和乱序问题,但UDP协议如果不能接受少量丢包,就必须自己设计有序和可靠性传输 ...
- 记一次修改DiyBox的经历(openwrt固件解包与打包)
吐槽几句 做技术的有无私造福人类的,也有耍流氓坑人的.说的不是DiyBox,而是"信利".信利就是一家犯贱.祸害大学生.助纣为虐的流氓公司,其所谓的"防私接"技 ...
- 5分钟,关于Python 解包,你需要知道的一切
题图:Photo by Elena Koycheva on Unsplash 导读:本文总结了 Python 解包操作的方方面面,文章略长,看本文时,身边最好有多个不同版本 Python 解释器的电脑 ...
最新文章
- SharePoint 2010 技巧系列: 控制Ribbon菜单权限(SiteActions的例子)
- 全球与中国太赫兹安检仪市场竞争状况及未来发展趋向分析报告2022-2028年版
- CFileDialog的基本使用
- spring mvc工作原理及组件说明
- nginx-URL重写
- Docker最全教程——从理论到实战(九)
- https://cwiki.apache.org/confluence/display/FLINK/FLIP-24+-+SQL+Client
- Spring笔记③--spring的命名空间
- php实现数字英文验证码,PHP英文数字验证码生成类
- 使用自动补全功能- MATLAB
- Linux学习总结(43)——企业运维最常用的150个Linux命令
- python官网的软件-Python编程软件 V3.9.0 官方最新版
- 致敬CondConv!Intel提出即插即用的“万金油”动态卷积ODConv
- aurelia_Aurelia历险记:创建自定义PDF查看器
- ALSA声卡驱动二之声卡的创建
- 2021-11-07-防火墙添加安全策略
- 黑鲨给电脑重装系统的详细步骤
- iOS12 捷径(热门推荐)
- Codeforces Round #545 (Div. 2) C. Skyscrapers
- IEEE Access投稿流程经验分享
热门文章
- SparkSQL使用之Thrift JDBC server
- [转]Creating Unit Tests for ASP.NET MVC Applications (C#)
- android-Bitmap,View,Canvas大综合
- Linux上vi的使用教程
- Raid信息丢失数据恢复及oracle数据库恢复验证方案
- inode与block详解
- 一步一步学Linq to sql(六):探究特性
- [diary]一下子更新了这么多
- 解决SqlServer2008修改表后保存时出现“save changes is not permitted…”问题
- JAVA线程池的分析和使用