博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
从强制解包看 Swift 的设计
阅读量:6258 次
发布时间:2019-06-22

本文共 2152 字,大约阅读时间需要 7 分钟。

从强制解包看 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()时会崩溃,原因是fooinit()中已经被设成了 nil,而foo在 Swift 中是 foo!。也就是说,因为 Swift 对 OC 变量的强转,导致了程序的崩溃。这是一个很容易忽略的问题,因为强转的时候,Xcode 不会给出任何的警告、报错或是提醒。而我们作为开发者,很容易忽略这样的错误,导致 runtime 的时候直接崩溃。

针对这种情况,我们来讨论下面三个问题。

  • Q: 为什么 Swift 要将 OC 中的变量如foo转为foo!而不是foo?

这是一个有争议的话题。我个人认为强制解包的方式会督促开发者考虑变量是否为 nil 的问题。在 OC 时代,声明变量一般不会考虑是否为空的问题;而在 Swift 时代,因为其是一门强安全性的语言,在变量定义时,必须确定变量是否为空。一般定义为非空有两种以下形式:

// force unwrappingvar foo = "Hello"// implicitly unwrappingvar 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 在语言设计思路上的差异。

其实nullablenonnull是 Swift 出来之后才引入 OC 的。所以一开始,OC 中的变量默认都是nullable,转变到 Swift 中,应该就是?。但是这样转化代价太大,我们所有变量都要在 Swift 中用if else或者guard来解包。所以为了写起来方便,Swift 干脆直接强转,故而现在这个机制也是一个历史遗留问题。

  • Q: Swift 如此这般导致混编 App 崩溃,没有提示的情况下程序员必须细细检查 nil 导致的 bug,这样设计强制解包的代价是否有点大?

这个 bug 在混编 App 中很容易出现,没有警告确实带来很大困扰。实际上早就在苹果的开发者论坛上被提出,Swift 组自己也开了个  要修,可惜最后不了了之。Github 上有人开发出了来解决这个问题。

我个人觉得这个问题苹果不重视的原因在于 Swift 和 OC 混编只是一个暂时的局面。Swift 取代 OC 是一个时间问题,所以解决混编中的问题都显得没有多大意义,在苹果内部也一直是低优先级。毕竟现在所有精力应该放在 Swift 上,随着时间的推移和 OC 的淡出,这个问题也将微不足道。

转载地址:http://xznsa.baihongyu.com/

你可能感兴趣的文章
常量,字段,构造方法 调试 ms 源代码 一个C#二维码图片识别的Demo 近期ASP.NET问题汇总及对应的解决办法 c# chart控件柱状图,改变柱子宽度 使用C#创建Windows服...
查看>>
安装 directx sdk 出现 S1023 解决
查看>>
Git-命令行-删除本地和远程分支
查看>>
SUPERSOCKET.CLIENTENGINE 简单使用
查看>>
第 7 章 异步输入输出
查看>>
ASP.NET应用使用Nginx做负载均衡遇到的一个问题
查看>>
Chapter 5 Blood Type——5
查看>>
在JSON中遇到的一些坑
查看>>
本文将介绍“数据计算”环节中常用的三种分布式计算组件——Hadoop、Storm以及Spark。...
查看>>
C#面试题(转载) SQL Server 数据库基础笔记分享(下) SQL Server 数据库基础笔记分享(上) Asp.Net MVC4中的全局过滤器 C#语法——泛型的多种应用...
查看>>
springmvc中controller内方法跳转forward?redirect?
查看>>
论坛程序推荐,区别
查看>>
spring mvc redirect 重定向 跳转并传递参数
查看>>
《止学》 [隋]文中子(王通)
查看>>
微信小程序之底部弹框预约插件
查看>>
基础知识 - Golang 中的正则表达式
查看>>
分享一个shell脚本的坑:grep匹配+wc取值 在脚本执行后的结果与手动执行结果不一致...
查看>>
【Clojure 基本知识】 关于函数参数的各种高级用法
查看>>
顺序图【6】--☆☆
查看>>
Docker 版本
查看>>