#iOS

前言

在平时的文字输入时,我总会在中文和英文,中文和数字中间添加一个普通空格 (U+0020)。在文本布局时不会显得那么拥挤,也一定程度上提升了阅读体验。前一段时间即刻 App 添加了一个中西文之前默认添加一个特殊空格的特性,体验之后发现,这样的宽度短于普通空格的特殊空格,即不会出现没有空格时过于拥挤的布局,也不会出现普通空格间距过大的问题。查阅了一些资料后,找到一篇关于 Sapce 的 Unicode 表,想不到空格还有这么多的种类。

之前的开发工作中,出现过一些,长文本在 iOS 设备中不换行的 Bug,这个问题曾经困扰了我许久,后来无意中发现了一个叫 NO-BREAK SPACE 的空格,其 Unicode 为 U+00A0。在 App 中的表现就是,设置了 UILabel 的 numberOfLines 属性为 0 同时 breakMode 设置为 byWords,含有该空格的文本也不会换行,即使限制了 UILabel 的宽度,换行时仍然会拆开单词换行。

鉴于即刻 App 这个新需求带来的完美效果,着手简单实现一下。不过不知道即刻选用的空格种类,这里经过多次比较之后,我使用了 U+2009,被称为 THIN SPACE 的空格。

实现

这个需求,我的第一反应就是使用正则来匹配给定字符串的如下情况

  • 中文+英文
  • 英文+中文
  • 中文+数字
  • 数字+中文
  • 中文+符号
  • 符号+中文
  • 忽略英文和数字的组合,即计量单位,如 10TB

想到用 Swift 来实现正则表达式,就会有点头皮发麻。先不说 NSRegularExpression 的部分 API 中还带有 NSRange。就是正则表达式里面,还需要添加 / 转义符,就是一个噩梦,可读性大大降低。不过,好在 Swift 5 新增的 Raw String 可以完美解决这个问题。用到的所有正则表达式如下

1
2
3
4
5
6
7
8
9
10
11
12
13
let chinese = #"[\u2E80-\u2FFF\u31C0-\u31EF\u3300-\u4DBF\u4E00-\u9FFF\uF900-\uFAFF\uFE30-\uFE4F]"# // 匹配中文

// 使用 tuple
// base 基础符号。单一符号,不成对
// open 与 close 成对出现的符号
let punc = (
base: #"[@&=_\,\.\?\!\$\%\^\*\-\+\/]"#,
open: #"[\(\[\{\'"<‘“]"#,
close: #"[\)\]\}\'">’”]"#
)

// 拉丁字符。数字、字母等
let latin = #"[A-Za-z0-9\u00C0-\u00FF\u0100-\u017F\u0180-\u024F\u1E00-\u1EFF]|\#(punc.base)"#

由于需要匹配的情况有前后之分,下面用一个数组,将上述的正则表达式组合成两个完整的正则表达式。通过 compactMap 获取到最后的 NSRegularExpression 实例数组。

1
2
3
4
let patterns = [
#"(\#(chinese))(\#(latin)|\#(punc.open))"#,
#"(\#(latin)|\#(punc.close))(\#(chinese))"#
].compactMap { try? NSRegularExpression(pattern: $0) }

最后,就可以通过 stringByReplacingMatches(in:options:range:withTemplate:) 方法,通过 template 替换原有的字符串了。

1
2
3
4
5
let unicode = "\u{2009}"
patterns.forEach { (regex) in
result = regex.stringByReplacingMatches(in: result, options: [], range: NSMakeRange(0, result.count), withTemplate: "$1\(unicode)$2")
}
return result

下面的 Gif 比较了不添加空格、添加普通空格和 U+2009 空格的区别。

Gif



原文地址

作为工程师,我们会花费 70% 的时间来调试。剩下的 20% 用于思考架构和与同事交流,最后的 10% 才是真正用于编码的时间。

调试就像是在犯罪电影中同时扮演侦探和嫌疑人。

Filipe Fortes via Twitter

因此,如何让 70% 的调试时间尽可能的愉快,就显得及其重要。LLDB 因此应运而生。Xcode 的 UI 调试工具展示了所有有用的调试信息,而不用敲任何 LLDB 指令。然而,控制台在我们日常工作中仍然扮演了重要的角色,下面介绍一些笔者在日常调试工作中经常使用的 LLDB 小技巧。

阅读更多



前些日子准备周会关于 Swift Extension 的分享时,翻看自己之前写过的 Extension 时。发现有些在可扩展性,以及易用性上并不尽如人意,这也让我在周会讨论中加入了如下议题。

  • 如何评判一个 Extension 是必要的,且有价值的
  • 编写 Extension 需要遵循哪些原则

阅读更多



Goku 的实现中,尝试了使用类似于 SnapKit 中,链式调用的方式,来构建 AlertView 的样式。具体使用如下

1
2
3
4
5
6
7
8
9
10
11
12
13
self.goku.presentAlert(animated: true, closure: { (make) in
make.theme
.actionSheet
.title("Okay/Cancel")
.message("A customizable action sheet message.")
.cancel("Cancel")
.destructive("OK")
.normal(["Button1", "Button2"])
.tapped({ (index) in
print("Tapped index is \(index)")
}
)
})

阅读更多

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×