最近抽空阅读了swift官方文档的Language Guide部分小节,下面记录一些知识盲点和个人认为比较有用的东西。
The Basics
第一个小节主要讲解了一些基本的东西,如var let等。也有一些知识点可以记录一下吧。
-
typealias
相当于oc里的tyepdef吧,可以用来取别名。
typealias AudioSample = UInt16
-
optional & nil
Swift’s nil isn’t the same as nil in Objective-C. In Objective-C, nil is a pointer to a nonexistent object. In Swift, nil isn’t a pointer—it’s the absence of a value of a certain type. Optionals of any type can be set to nil, not just object types.
大概的意思是说oc里的nil是指向了一个不存在的对象,而在swift中,nil不是指针,它是一个确定类型的缺失(= =蹩脚的英文),任何可选类型可以设置成nil,不只是对象类型。网上也有很多资料都介绍过可选类型,可选其实就是对某个类型进行了一层包装,里面包含了some和none,none就是这个nil,some就是具体的值。
-
assert:断言
大部分用来调试使用,类似guard,但是不符合条件程序会直接退出。
let age = -3
assert(age >= 0, "A person's age can't be less than zero.")
-
Error handle
异常处理,不过目前只在调用别人的api的时候用到过= =。
do {
try caThrowAnError(age: 1000)
} catch AgeEorror.negative {
print(AgeEorror.negative.rawValue)
} catch AgeEorror.tooLarge {
print(AgeEorror.tooLarge.rawValue)
} catch {
print("未知错误~")
}
enum AgeEorror: String, Error {
case negative = "输入的年龄不能是负数!"
case tooLarge = "不可能活那么久!"
}
func caThrowAnError(age: Int) throws {
if age < 0 {
throw AgeEorror.negative
} else if age > 200 {
throw AgeEorror.tooLarge
}
}
这里结合枚举使用,抛出的错误类型必须遵循Error协议。
Basic Operators
这一小节比较简单,讲解了大部分操作符。相信有点编程基础的应该都会一眼带过,但也抽两个知识点意思意思吧!
-
??
这个操作符在平时开发中使用还是非常频繁的,至少本人平时经常使用,有点像是三目运算符的感觉。
var a: Int?
let b = a ?? 0
如上代码,大致的意思就是假设a有值,即a不为nil的时候会把a赋值给b,如果a为nil则把0赋值给b。
-
区间运算符[...]
这个操作符在遍历集合等场景使用较多。
let names = ["1","2","3","4","5"]
for name in names[...3] {
print(name)
}
没错,就是你心里想的那样,遍历第0-3个元素,也可以加入<操作符,如[..<3]表示遍历第0,1,2个元素。
Strings and Characters
这一小节主要是讲解了Swift中的字符串,有几个知识点在上一篇文章Swift之旅_Welcome to Swift有提到过,主要是一个字符串可以用”””来表示多行,还有新增了一个Substring类型,具体的可以参考上一篇文章。
Collection Types
这一小节讲解的是Swift中的集合类型,主要是Array,Dictionary,Set。都比较简单,而且Swift中用起来很方便。但是因为Set平时用的很少,我就着重看了一下。
A type must be hashable in order to be stored in a set—that is, the type must provide a way to compute a hash value for itself. A hash value is an Int value that is the same for all objects that compare equally, such that if a == b, it follows that a.hashValue == b.hashValue.
Set是一个无序不重复的集合,Set中的元素必须是可哈希的。直接一直不知道哈希是什么鬼。最近一次学习的时候知道了哈希其实就是一个单向散列函数。单项散列函数可以将一串数据计算得到一个独一无二的值,所以也不难理解为啥Set中的元素必须是可哈希的了,因为Set是不重复的。
Set集合中一些常用的操作和对应的效果,官方文档中的这幅图非常形象。
Control Flow
控制流,讲解了一些循环和控制语句。
-
for循环
常见的都很简单,不过文档中倒是提到了一种比较特别的循环方式,可以以一个数的倍数进行循环:
let minutes = 60
let minuteInterval = 5
for tickMark in stride(from: 0, to: minutes, by: minuteInterval) {
// render the tick mark every 5 minutes (0, 5, 10, 15 ... 45, 50, 55)
}
//以下写法可以到达hours,相当于小于等于吧
let hours = 12
let hourInterval = 3
for tickMark in stride(from: 3, through: hours, by: hourInterval) {
// render the tick mark every 3 hours (3, 6, 9, 12)
}
此外我们都知道Swift中的switch语句是不用手动写break的,Swift也提供了一个修饰符可以让switch像c一样, fallthrough,这个修饰符可以让swift的switch语句匹配到对应的值之后继续向下落。
let a = 5
switch a {
case 5,6,7,8,9:
print("case 1")
fallthrough
case 1,2,3,4,5:
print("case 2")
fallthrough
default:
print("default")
}
Functions
这个小节就比较重要了,讲解的是Swift中的函数。
-
Variadic Parameters-可变参数
可变参数在绝对大多数开发语言中都存在,Swift也不列外。Swift中使用可变参数也是非常简单。
func arithmeticMean(_ numbers: Double...) -> Double {
var total: Double = 0
for number in numbers {
total += number
}
return total / Double(numbers.count)
}
arithmeticMean(1, 2, 3, 4, 5)
// returns 3.0, which is the arithmetic mean of these five numbers
arithmeticMean(3, 8.25, 18.75)
// returns 10.0, which is the arithmetic mean of these three numbers
-
In-Out Parameters
在函数内部是无法直接更改参数的值的,或者这样说比较贴切,参数在函数内部是let形式的。若想要达到更改调用函数时传入的参数就需要用到inout这个修饰符。
func swapTwoInts(_ a: inout Int, _ b: inout Int) {
let temporaryA = a
a = b
b = temporaryA
}
Closures
block的作用和oc的大致相同,但是这里有多个注意点。
-
$0
Swift中的block可以直接用$0,$1...表示第1,2…参数,这样可以直接不用写明参数 和 in,这样写起来代码似乎是清爽了很多。
let names = ["Chris", "Alex", "Ewa", "Barry", "Daniella"]
reversedNames = names.sorted(by: { $0 > $1 } )
-
可以直接将函数赋值给block
只要参数和返回值都相同,就可以直接将函数赋值给block
var block: (()->Int) = test
func test() -> Int {
return 0
}
-
Escaping Closures
逃逸闭包,相信很多同学都碰到过Xcode自动帮你在函数参数中的block前面加上@escaping修饰符。
A closure is said to escape a function when the closure is passed as an argument to the function, but is called after the function returns. When you declare a function that takes a closure as one of its parameters, you can write @escaping before the parameter’s type to indicate that the closure is allowed to escape.
当闭包作为函数参数传递,但是是在函数返回后调用时,闭包被称为逃逸闭包。当你声明一个有闭包参数的函数时,你可以在参数前面写上@escaping表明闭包时允许逃逸的。
One way that a closure can escape is by being stored in a variable that is defined outside the function. As an example, many functions that start an asynchronous operation take a closure argument as a completion handler. The function returns after it starts the operation, but the closure isn’t called until the operation is completed—the closure needs to escape, to be called later.For example:
闭包可以逃避的一种方法是存储在函数之外定义的变量中。例如,启动异步操作的许多函数都使用闭包参数作为完成回调。函数在启动操作后返回,但是在操作完成之前不会调用闭包-为了可以延迟调用,闭包需要时可逃逸的。例如:
var completionHandlers: [() -> Void] = []
func someFunctionWithEscapingClosure(completionHandler: @escaping () -> Void) {
completionHandlers.append(completionHandler)
}
The someFunctionWithEscapingClosure(_:) function takes a closure as its argument and adds it to an array that’s declared outside the function. If you didn’t mark the parameter of this function with @escaping, you would get a compile-time error.
someFunctionWithEscapingClosure函数有一个闭包参数并且把它添加到了函数外部的一个数组中。如果你不在函数参数前面加上@ escaping,你会在编译的时候得到一个error。
其实大概的意思就是如果这个block是作为函数参数使用,并且是在函数执行完毕之后调用的,就需要在函数的block参数前面加上@escaping修饰符。其实这个大多时候XCode帮我们做了。大家了解一下就行。
-
@autoclosure
这个原文有点难翻译= =,直接上一段代码吧。
func test3(tBlock: @autoclosure ()->String) {
print(tBlock())
}
test3(tBlock: "World")
大概意思就是和代码一样吧,感觉就是加上@autoclosure之后,调用函数的时候可以直接传入和闭包返回值相同类型的参数。