服务器之家:专注于VPS、云服务器配置技术及软件下载分享
分类导航

PHP教程|ASP.NET教程|Java教程|ASP教程|编程技术|正则表达式|C/C++|IOS|C#|Swift|Android|VB|R语言|JavaScript|易语言|vb.net|

服务器之家 - 编程语言 - Swift - Swift踩坑实战之一个字符引发的Crash

Swift踩坑实战之一个字符引发的Crash

2022-07-27 10:14汉森 Swift

swift通常都是通过对应的signal来捕获crash,下面这篇文章主要给大家介绍了关于Swift踩坑实战之一个字符引发的Crash的相关资料,文中通过实例代码介绍的非常详细,需要的朋友可以参考下

最近因为一个字符引发了 Crash,因为实际的业务场景不便描述,这里便用一段测试代码作说明。

话不多说,直接上代码:

?
1
2
3
4
5
6
7
8
let testCharacters: Set<Character> = ["!", "\"", "$", "%", "&", "'", "+", ",", "<", "=", ">", "@", "[", "]", "`", "{", "}"]
let testString = "@`Hello World`!"
var result: UInt8 = 0
for character in testString {
    if testCharacters.contains(character) {
    result += character.asciiValue!
    }
}

上面的代码做的事情是:取出 testString 里特定字符的 ASCII 码,然后相加。

我们来 Review 下这段代码,有经验的同学应该立马嗅到了代码里的坏味道:character.asciiValue! 这里用了强解。

那这里的强解用得合理吗?因为定义在 testCharacters 里的字符肯定都有对应的 ASCII 码,咋一看这里用强解也没关系。

但是,如果我们实际跑一下,就会出现因为 asciiValue 为 nil 的强解 Crash 了。这是为什么呢?

关键在于 testString 里面包含了 全角字符。testString 里的后一个 ` 是一个全角字符,它是没有 asciiValue 的。

我们可以在 Swift Playgrounds 里执行下面的代码得到答案:

?
1
2
3
4
5
6
7
8
9
10
11
let halfWidth = "`"
halfWidth.lengthOfBytes(using: .utf8) // 1
halfWidth.first!.isASCII // true
halfWidth.first!.asciiValue // 96
 
let fullWidth = "`"
fullWidth.lengthOfBytes(using: .utf8) // 3
fullWidth.first!.isASCII // false
fullWidth.first!.asciiValue // nil
// Character 实现 Equatable 协议,判断出两个值是相等的。
halfWidth == fullWidth // true

从上面代码执行结果可以看到,halfWidth 这个半角字符占一个字节长度,对应的 ASCII 码为 96 而全角字符 fullWidth 占三个字节长度,其 asciiValue 为空的。

Swift 数组的 contains 方法利用的是 Equatable 协议 , 从上面代码里 halfWidth == fullWidth 的结果为 true 来看,Character 实现的 Equatable 协议并没有考虑字符全角/半角的情况。

用肉眼看,完全看不出字符有何不同,而 contains 方法结果为 true 也影响了我们的判断,以为这个强解是 OK 的,稍不注意就导致了 Crash。

最后,从维基百科上整理了关于全角/半角的历史知识:

在早期的计算机中,英语或拉丁字母语言使用的系统,每一个字母或符号,都是使用一字节的空间(一字节由 8 比特组成,共256个编码空间)来储存;而汉语、日语及韩语文字,由于数量大大超过256个,故惯常使用两字节来储存一个字符。所以这原本是编码层面的“单字节”“双字节”的问题。

当时的电脑使用等宽字体(如DOS、部分文字编辑器等)时,字体也就顺应这种编码形式,将中日韩文字的宽度绘制成拉丁字母和数字的两倍,这样字符的编码存储和显示宽度可以一一对应起来:

  • 单字节文字 显示成 半宽,
  • 双字节文字 显示成 全宽。

因此当时的用户就开始习惯称中、日、韩等文字为 全角字符,而称拉丁字母或数字为 半角字符。

但是,后来计算机的文字编码技术已经发生很大变化,存储一个字符可能用一个、两个、四个或者更多的字节。一个英文字符即使显示为半宽,依照不同的编码方式,并不一定是用一个字节存储。

因此,现在字符编码存储和字符显示宽度的已经没有一一对应关系。

但是由于字符编码和字形宽度曾经的对应关系,很多用户一直习惯性地使用"全角/半角"词汇。

因此现在的 全角字 可能是指:

  • 用两个字节存储的字符
  • ASCII(所谓半角英文和数字)以外所有的字符
  • 显示上字身宽度为一比一正方形的字形。

总结

到此这篇关于Swift踩坑实战之一个字符引发Crash的文章就介绍到这了,更多相关Swift字符引发的Crash内容请搜索服务器之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持服务器之家!

原文链接:https://juejin.cn/post/7066723364991139870

延伸 · 阅读

精彩推荐
  • Swiftswitch循环所支持的数据类型案例分析

    switch循环所支持的数据类型案例分析

    这篇文章主要介绍了switch循环所支持的数据类型,本文通过实际案例讲解的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下...

    一生的风景5912021-01-15
  • SwiftSwift中图片资源使用流程的优化方法详解

    Swift中图片资源使用流程的优化方法详解

    这篇文章主要给大家介绍了关于Swift中图片资源使用流程的优化方法的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参...

    AntScript11862021-01-09
  • Swiftswift中c风格的for循环执行效率

    swift中c风格的for循环执行效率

    这篇文章主要介绍了swift中c风格的for循环执行效率 的相关资料,需要的朋友可以参考下...

    无敌最孤单11212020-12-29
  • SwiftSwift算法之二叉树实现的方法示例

    Swift算法之二叉树实现的方法示例

    二叉树是计算机科学中最基本也是最重要的树型结构,最常见的二叉树生成算法通常是使用递归或者其他描述类语言的方法来实现。本文主要介绍了Swift算法...

    李峰峰9062021-01-05
  • Swiftswift 可选型的使用详解

    swift 可选型的使用详解

    可选性是Swift提供的一个特殊类型,它为我们编写程序提供便利的条件。这篇文章主要介绍了swift 可选型的使用详解,非常不错具有参考借鉴价值,需要的朋...

    追到梦的魔术师8912020-12-30
  • Swiftswift4 使用DrawerController实现侧滑菜单功能的示例代码

    swift4 使用DrawerController实现侧滑菜单功能的示例代码

    这篇文章主要介绍了swift4 使用DrawerController实现侧滑功能的示例代码,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧...

    朋也4942021-01-12
  • SwiftSwift学习笔记之逻辑分支与循环体

    Swift学习笔记之逻辑分支与循环体

    这篇文章主要给大家介绍了关于Swift学习笔记之逻辑分支与循环体的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考...

    大基本功7422021-01-09
  • Swiftswift在IOS应用图标上添加提醒个数的方法

    swift在IOS应用图标上添加提醒个数的方法

    本文是通过swift语言实现在应用图标右上角添加消息个数提醒的功能,非常不错,具有参考借鉴价值,感兴趣的朋友一起看下吧...

    JackWang-CUMT8702020-12-29