强制解包看 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 的淡出,这个问题也将微不足道。
强制解包看 Swift 的设计的更多相关文章
- 从强制解包看 Swift 的设计
从强制解包看 Swift 的设计 不知道大家有没有发现,在一个 Objective-C 和 Swift 混编的 App 中,当把一个 OC 中的参数转到 Swift 时,Swift 会自动把这个变量进 ...
- Swift中的Optional类型 (可选类型)与强制解包 ? !
我们在swift的开发中会经常遇见?和! ,理解这两个符号深层次的内容对我们的开发是相当有利的: 目前网上对swift3.0的教程还相当的少,如果去搜索会发现早期的说法,在定义变量的时候,swift是 ...
- 关于Python 解包,你需要知道的一切
解包在英文里叫做 Unpacking,就是将容器里面的元素逐个取出来(防杠精:此处描述并不严谨,因为容器中的元素并没有发生改变)放在其它地方,好比你老婆去菜市场买了一袋苹果回来分别发给家里的每个成员, ...
- Python中的可变、不可变对象和赋值技巧序列解包
可变对象和不可变对象 在python中一切皆对象.在Python中不存在所谓的值传递调用,一切传递都是对象的引用,也可认为是传址. python中,对象分为可变(mutable)和不可变(immuta ...
- php归档格式:phar文件详解(创建、使用、解包还原提取)
转载一篇,突然遇到一个冷知识,phar的东东,貌似和jar.war是一种鬼. 重点使用一下下面这个东东,就能解包出来东东了. $phar = new Phar('lib/yunke.phar', 0) ...
- apk 解包 打包
APK应用程序的解包.修改.编辑.汉化.打包及应用 前两讲主要讲玩机的最基本的知识,集中在如何刷机.本讲是进级的内容,来谈谈与apk应用程序有关的知识,内容包括akp文件的解包.打包.反编辑.解析.汉 ...
- Python中的参数解包:`*`表达式和 `**`表达式
目录 1.参数解包:方法调用中的*表达式和**表达式 2.参数解包:方法定义中的*表达式和**表达式 3.在元组,列表,集合和字典中解包 4.Extended Unpacking:赋值表达式左边的*表 ...
- RocketMQ详解(四)核心设计原理
专题目录 RocketMQ详解(一)原理概览 RocketMQ详解(二)安装使用详解 RocketMQ详解(三)启动运行原理 RocketMQ详解(四)核心设计原理 RocketMQ详解(五)总结提高 ...
- MonoTouch 二三事(三)mono mkbundle 打包程序的解包支持
2014.10.06 更新 编写了 IDA Pro 的插件,用来解包和打包 mkbundle程序,请参见 https://github.com/binsys/MKBundleManager 许久以后, ...
随机推荐
- [转]使用sklearn进行集成学习——理论
转:http://www.cnblogs.com/jasonfreak/p/5657196.html 目录 1 前言2 集成学习是什么?3 偏差和方差 3.1 模型的偏差和方差是什么? 3.2 bag ...
- JavaScript Break 和 Continue 语句
1.break:终止本层循坏,继续执行本次循坏后面的语句: 当循坏有多层时,break只会跳过一层循坏 2.continue:跳过本次循坏,继续执行下次循坏 对于for循环,continue执行后,继 ...
- iOS 从url中获取文件名以及后缀
//这里有一个模拟器沙盒路径(完整路径) NSString* index=@"/Users/junzoo/Library/Application Support/iPhone Simulat ...
- mysql加密解密方式用法
如果你使用的正是mysql数据库,那么你把密码或者其他敏感重要信息保存在应用程序里的机会就很大.保护这些数据免受黑客或者窥探者的获取是一个令人关注的重要问题,因为你既不能让未经授权的人员使用或者破坏应 ...
- Git命令行和Xcode结合使用
现在一直使用Git来管理代码,对于有强迫症的我来说,依旧选择了命令行,下面这段话可以更好的解释我为什么喜欢使用终端敲命令. There are a lot of different ways to u ...
- hadoop、Storm该选哪一个
如果hadoop.Storm还感觉混要,那么此篇文章将帮助你把他们完全区分 可以带着下面问题来阅读本文章: 1.hadoop.Storm各是什么运算 2.Storm为什么被称之为流式计算系统 3.ha ...
- 一道CVTE前端二面笔试题
题目:给你一个数组,输出数组中出现次数第n多的数字; 比如:[1,1,1,2,2,2,3,3,4,4,5,5,6,6,7]; 1---3次 2---3次 3---2次 4---2次 5---2次 6- ...
- Unity 类似FingerGestures 的相机跟随功能
本文原创,转载请注明出处:http://www.cnblogs.com/AdvancePikachu/p/6555188.html 最近在做一款VR项目,有一个查看功能,分为自由查看和跟随查看. 自由 ...
- 200_longest-palindromic-substring
/*@Copyright:LintCode@Author: Monster__li@Problem: http://www.lintcode.com/problem/longest-palind ...
- placeholder各种浏览器兼容问题
只要在页面上引入placeholder.min文件,再以$('input,textarea').placeholder(); 就可以兼容ie等各种浏览器. placeholder.min.js文件链接 ...