swift语法更新
- SE-0200 原始字符串
添加了创建原始字符串的功能,其中\
和""
被解释为这些文字符号本身,而不是转义字符或字符串终止符。这使得许多功能更加容易实现,比如正则表达式。
要使用原始字符串,请在字符串前放置一个或多个#
号,如下所示:
//正则表达式 regex1 == regex2
let regex1 = "\\\\[A-Z]+[A-Za-z]+\\.[a-z]+"
let regex2 = #"\\[A-Z]+[A-Za-z]+\.[a-z]+"#
let keypaths = #"Swift 中的 keypaths 格式像这样: \Person.name ."#
//原始字符串中包含#
let anotherString = ##"这是一个包含“#”的原始字符串"##
//多行字符串的原始字符串
let multiline = #"""
这是一个多行字符串:,
“我才是
多行字符串”。
"""#
//原始字符串中插值
let answer = 42
let dontpanic = #"宇宙的终极答案是:\#(answer)."#
请注意,我如何使用
\(answer)
来使用字符串插值\(answer)
将被解释为字符串中的字符,因此当您希望在原始字符串中进行字符串插值时,必须添加额外的`#'
2.SE-0235 在标准库中引入“Result”类型,使我们能够更简单、更清晰地处理复杂代码(如异步API)中的错误。
swift的“Result”类型实现为具有两种情况的枚举:“success”和“failure”。两者都是使用泛型实现的,这样它们就可以有一个相关值,但是“failure”必须是符合swift的“Error”类型。(如果你之前使用过这个库Result,你会发现他们几乎一模一样)
3.SE-0228字符串插值系统的升级:新增了用于调试struct
的输出方法,如果你需要自定义某结构体的输出你需要扩展String.StringInterpolation
并实现appendInterpolation()
方法
struct User {
var name: String
var age: Int
}
extension String.StringInterpolation {
mutating func appendInterpolation(_ value: User) {
appendInterpolation("My name is \(value.name) and I'm \(value.age)")
}
}
let user = User(name: "Guybrush Threepwood", age: 33)
print("User details: \(user)")
//输出:User details: My name is Guybrush Threepwood and I'm 33
//格式化插值到字符串
extension String.StringInterpolation {
mutating func appendInterpolation(_ number: Int, style: NumberFormatter.Style) {
let formatter = NumberFormatter()
formatter.numberStyle = style
if let result = formatter.string(from: number as NSNumber) {
appendLiteral(result)
}
}
}
let number = Int.random(in: 0...100)
let lucky = "The lucky number this week is \(number, style: .spellOut)."
print(lucky)
//输出:The lucky number this week is sixty-three.
在此基础上用户可以扩展更多类型的差之方法如:输出小数位数,控制电话号码格式,邮件格式等等,更多例子可以查看下方whats-new-in-swift-5-0
注意:旧
_ExpressibleByStringInterpolation
协议已被删除; 任何使用此协议的代码都需要针对新设计进行更新。一个#if compiler
块可用于条件化4.2和5.0之间的代码,例如:
#if compiler(<5.0)
extension MyType : _ExpressibleByStringInterpolation { ... }
#else
extension MyType : ExpressibleByStringInterpolation { ... }
#endif
4.SE-0216新增语法糖 @dynamicCallable
,@dynamicallable
是swift 4.2的@dynamicmemberlookup
的扩展,其作用相同:使swift代码更容易与动态语言(如python和javascript)一起工作。
5.SE-0192新增 @unknown
关键字,此关键词可以用在switch语句中,Swift它要求所有switch语句覆盖所有情况,但有时我们需要忽略一些枚举值,我们使用default去处理忽略的情况,但当我们新增一个枚举类型,我们的switch语句没有更改,他也不再会提示错误,因为default以及处理了新的情况,为了更好地提示开发者使用@unknown default
和原default具有相同的功能,并且编译器回升弄成一个警告⚠️提醒用户没有处理所有情况:
enum PasswordError: Error {
case short
case obvious
case simple
}
//这个方法没有任何提示
func showOld(error: PasswordError) {
switch error {
case .short:
print("Your password was too short.")
case .obvious:
print("Your password was too obvious.")
default:
print("Your password was too simple.")
}
}
func showNew(error: PasswordError) {
switch error { //此行警告⚠️Switch must be exhaustive
case .short:
print("Your password was too short.")
case .obvious:
print("Your password was too obvious.")
@unknown default:
print("Your password wasn't suitable.")
}
}
6.SE-0230修改try
的嵌套方式
struct User {
var id: Int
init?(id: Int) {
if id < 1 {
return nil
}
self.id = id
}
func getMessages() throws -> String {
// complicated code here
return "No messages"
}
}
let user = User(id: 1)
let messages = try? user?.getMessages()
在swift4.2中上方代码中messages的类型将会是一个String??
类型,在swift5中你会得到一个String?
类型,这意味着,链式调用不会再使可选值发生嵌套。
7.SE-0225整数类型新增函数isMultiple(of:)
判断是否是一个数的倍数
let rowNumber = 4
if rowNumber.isMultiple(of: 2) {
print("Even")
} else {
print("Odd")
}
8.SE-0218字典类型新增方法compactMapValues()
,用于转换字典value
的类型(空值将被移除)
let times = [
"Hudson": "38",
"Clarke": "42",
"Robinson": "35",
"Hartis": "DNF"
]
//将[String:String]转换成[String:Int]
let finishers1 = times.compactMapValues { Int($0) }
let finishers2 = times.compactMapValues(Int.init)
// ["Hudson": 38, "Clarke": 42, "Robinson": 35]
9.SE-0213通过字面量强制初始化,
如果T
符合其中一个ExpressibleBy*
协议并且literal
是一个文字表达式,那么T(literal)
将使用一个和T
的类型相同的构造方法,而不是使用T
的默认构造函数
struct Q: ExpressibleByStringLiteral {
typealias StringLiteralType = String
var question: String
init?(_ possibleQuestion: StringLiteralType) {
return nil
}
init(stringLiteral str: StringLiteralType) {
self.question = str
}
}
_ = Q("ultimate question") // 'nil'
_ = "ultimate question" as Q // Q(question: 'ultimate question')
10.SR-5719在Swift 5模式下,@autoclosure参数不能再转发到另一个函数调用中的@autoclosure参数。相反,必须使用()显式调用函数值;调用本身被包装在隐式闭包中,以确保与swift 4模式中的行为相同。
func foo(_ fn: @autoclosure () -> Int) {}
func bar(_ fn: @autoclosure () -> Int) {
foo(fn) // ❌ `fn` can't be forwarded and has to be called
foo(fn()) // ✅
}
11.SR-695在Swift 5模式中,返回Self
的类方法不能再被返回非最终具体类类型的方法重写。此类代码不是类型安全的,需要更新。
class Base {
class func factory() -> Self { ... }
}
class Derived : Base {
class override func factory() -> Derived { ... }
}
12.SR-5581协议现在可以将它们的符合类型约束为给定类的子类。支持两种等效形式:
protocol MyView : UIView { ... }
protocol MyView where Self : UIView { ... }
请注意,Swift 4.2接受了第二种形式,但它没有完全实现,有时可能会在编译时或运行时崩溃。
swift5适配遇到的问题
升级xcode10.2后代码几乎无需调整,如果你使用了阿里的HandyJson,会因为Swift 5 Type Metadata的变动导致编译失败,在本文编写前该项目已提交更新,但版本号4.2.1
未发生变化,意味着使用cocoapods集成的同学使用pod update
将无法更新代码。解决方法先移除podfile
文件中的handyjson进行pod update
,清空cocoapods
缓存,添加handyjson
到podfile
重新pod upate
或者直接切换到5.0分枝
pod 'HandyJSON', git: '[https://github.com/alibaba/HandyJSON.git](https://github.com/alibaba/HandyJSON.git)' , branch: 'dev_for_swift5.0'
XCode 10.2更新
- Interface Builder:双击故事板不再缩放。使用触控板上的捏合手势进行缩放或按住Option并滚动。
- LLDB调试:可以使用LLDB调试在闭包内的表达式
$0,$1......
- LLDB现在支持C的可变长数组
- LLDB调试器有一个新的命令别名,
v
用于“帧变量”命令,用于在当前堆栈帧中打印变量。因为它绕过表达式评估器,v比p或po优先级更高,并且速度更快 - Xcode使用SSH配置来确定应该使用哪个SSH密钥来验证远程存储库。
- 更多内容浏览下方文档
Xcode 10.2 Release Notes
参考文档
1.whats-new-in-swift-5-0
2.swift change Log
3.swift-5-released
4.Xcode 10.2 Release Notes