2020-08-14 08:11:16 登录注册 RSS

当前位置: 公理网 >> 显明公道 >> 从强制解包看Swift的设计

从强制解包看Swift的设计
发布时间:02-14| 来源:公理网 | 点击发表评论
1721232-2d1a4dc1adafb7d8.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240"alt=""/>

不知道大家有没有发现,在一个Objective-C和Swift混编的App中,当把一个OC中的参数转到Swift时,Swift会自动把这个变量进行强制解包。举个例子,我在OC中定义这样一个变量:


@property(nonatomic,copy)NSString*foo;

它转成Swift就变成了这样:


varfoo:String!

这样看上去合情合理。Swift中有String?和String!两种形式,但OC中没有NSString?和NSString!,当Swift无法区分OC中的变量是不是nil的时候,一律强行转化为非空参数。这样设计体现了Swift强安全性语言的特性。


但是这时候问题来了。我们回到上文中的例子,假如OC中对?foo的使用如下:


@property(nonatomic,copy)NSString*foo;
-(void)secretFunc{
//一些诡异复杂的操作
self.foo=nil;
}

然后我们在Swift中这样调用:


funcinit(){
objectiveCObject.secretFunc()
funccalcLen()-Int{
returnobjectiveCObject.foo.characters.count
}

上面这段Swift代码执行到calcLen()时会崩溃,原因是foo在init()中已经被设成了nil,而foo在Swift中是?foo!。也就是说,因为Swift对OC变量的强转,导致了程序的崩溃。这是一个很容易忽略的问题,因为强转的时候,Xcode不会给出任何的警告、报错或是提醒。而我们作为开发者,很容易忽略这样的错误,导致runtime的时候直接崩溃。


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

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

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


//forceunwrapping
varfoo="Hello"
//implicitlyunwrapping
varfoo: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中用ifelse或者guard来解包。所以为了写起来方便,Swift干脆直接强转,故而现在这个机制也是一个历史遗留问题。

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

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


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

最新新闻

手机浏览

公理网 版权所有

公理网 Total 0.037319(s) query 6, 报料QQ:点击这里

给我发消息