var、let
var声明变量,表示变量可修改,如var a = 3,可以对a进行修改,a=4
let声明变量,表示变量不可修改,如let a = 3,那么就不可以对a进行修改(a=4报错)
简单来说,var表示这个变量,可以指向新的内存地址,而let,则不能指向新的内存地址
staic、class、final
static修饰的方法,变量,表示静态方法、变量,可以用于结构体、协议、类中,而在类中使用时,它和它的子类共享,但是不能被子类重写
class修饰的方法,变量,表示类方法、变量,只能用在类中,子类可以重写;
需要注意的是,class通常修饰方法,如果修饰变量的话,只能是计算型变量。
final关键字在大多数的编程语言中都存在,表示不允许对其修饰的内容进行继承或者重新操作。Swift中,final关键字可以在class、func和var前修饰。
defer
1、defer语句在代码块(方法、闭包等,可以理解为大括号包装起来的代码)作用域退出之前执行,也就是代码块中其他应该执行的代码都执行完了,才执行defer中的代码
2、一个代码块允许多个defer,多个defer执行的顺序 从后到前
3、defer 语句块中的代码, 会在当前作用域结束前调用, 常用场景如异常退出后, 关闭数据库连接
4、需要注意的是, 如果有多个 defer, 那么后加入的先执行
func someQuery() -> ([Result], [Result]){
let db = DBOpen("xxx")
defer {
db.close()
}
guard results1 = db.query("query1") else {
return nil
}
guard results2 = db.query("query2") else {
return nil
}
return (results1, results2)
}</pre>
//需要注意的是, 如果有多个 defer, 那么后加入的先执行
func someDeferFunction() {
defer {
print("\(#function)-end-1-1")
print("\(#function)-end-1-2")
}
defer {
print("\(#function)-end-2-1")
print("\(#function)-end-2-2")
}
if true {
defer {
print("if defer")
}
print("if end")
}
print("function end")
}
someDeferFunction()
// 输出
// if end
// if defer
// function end
// someDeferFunction()-end-2-1
// someDeferFunction()-end-2-2
// someDeferFunction()-end-1-1
// someDeferFunction()-end-1-2</pre>
dynamic
由于 swift 是一个静态语言, 所以没有 Objective-C 中的消息发送这些动态机制, dynamic 的作用就是让 swift 代码也能有 Objective-C 中的动态机制, 常用的地方就是 KVO 了, 如果要监控一个属性, 则必须要标记为 dynamic
typealias
给一个类型取别名,例
public typealias RxTime = Date
用于协议中定义了泛型时,在实际使用的时候,需要给这个泛型确定一个真实类型
associatedtype
简单来说就是 protocol 使用的泛型,一般联合typealias使用
protocol ListProtcol {
associatedtype Element
func push(_ element:Element)
func pop(_ element:Element) -> Element?
}
实现协议的时候, 可以使用 typealias 指定为特定的类型, 也可以自动推断, 如
class IntList: ListProtcol {
typealias Element = Int // 使用 typealias 指定为 Int
var list = [Element]()
func push(_ element: Element) {
self.list.append(element)
}
func pop(_ element: Element) -> Element? {
return self.list.popLast()
}
}
class DoubleList: ListProtcol {
var list = [Double]()
func push(_ element: Double) {// 自动推断
self.list.append(element)
}
func pop(_ element: Double) -> Double? {
return self.list.popLast()
}
}
where
可以限定泛型的类
where语句在if中使用时,在swift4及以后,被,代替
extension ListProtcol where Element == Int {
func isInt() ->Bool {
return true
}
}
case
case可在if、switch语句中使用
//case 不只是在switch中使用
//注意,where语句在if中使用时,在swift4及以后,被,代替
/*
if 中使用case,where
*/
let tempInt = 23
if case 10...30 = tempInt{
print("if case")
}
if case 10...30 = tempInt, tempInt<25{
print("if case where")
}
if tempInt<30,tempInt>20{
print("if where")
}
/*
switch 中使用where
*/
let pointTemp = (10,20)
switch pointTemp {
case (let x,let y) where x == y/2 :
print ("switch中使用where")
default:
print("default")
}
/*
for in中使用where、case
*/
for i in 1..<20 where I>10{
print("for in中使用where,i = \(i)")
}
for case let i in 1..<20 where I>10{
print("for in中使用case where,i = \(i)")
}
guard
guard,保证符合条件,否则怎样(guard关键字,需要return或者throw配合使用,所以一般必须在函数体中使用)
func testGuard(x:Int?)->(){
guard let testGuardTemp = x,testGuardTemp>20 else {
print("guard的用法")
return
}
print("guard的用法:",testGuardTemp)
return
}
testGuard(x:nil)
testGuard(x: 23)
//guard与if的区别,在于guard中进行可选型解包而声明的变量,能在方法体内下继续使用,if则只能在if体内使用
guard 和 if 类似, 不同的是, guard 总是有一个 else 语句, 如果表达式是假或者值绑定失败的时候, 会执行 else 语句, 且在 else 语句中一定要停止函数调用 例如
guard 1 + 1 == 2 else {
fatalError("something wrong")
}
常用使用场景为, 用户登录的时候, 验证用户是否有输入用户名密码等
guard let userName = self.userNameTextField.text,
let password = self.passwordTextField.text else {
return
}
inout
输入输出参数, 如:
func swap( a: inout Int, b: inout Int) {
let temp = a
a = b
b = temp
}
var a = 1
var b = 2
print(a, b)// 1 2
swap(a: &a, b: &b)
print(a, b)// 2 1</pre>
weak、unowned
两者都是弱引用,都只能使用在类实例上面
weak修饰的变量,对象释放后自动置为nil(因此被标记为 @weak
的变量一定需要是 Optional
值)
weak弱引用多用于通常的解决循环引用问题场景。
unowned修饰的变量,对象释放后不会自动置为nil,仍然保留释放对象的地址,所以可能发生野指针问题
unowned无主引用用于一个属性允许设置为 nil
,而另一个属性不允许设置为 nil
,并会造成潜在的强引用循环的场景。
从安全角度来说,weak优于unowned,但是从性能上说,unowned优于weak(weak的实质是对unowned的封装,包裹了一个可选值)
1、Unowned和Weak的使用时机
Unowned一般使用在其所修饰的对象和所处的block环境的生命周期一致的时候。 简单来说,Unowned修饰的对象,在整个block的使用期间都应该是有效的,即不可为nil。
Weak则可以使用为block 的生命周期超出其对象进行修饰。 意思是可以修饰可能变成nil的对象。用Swift中的话语来说就是Optional对象。
相比之下,weak的使用范围更加广泛,如果不考虑性能的话,我们大可以无论什么情况都使用weak将会更加安全。然而,既然Unowned存在,必将有他的意义 —— 出于性能考虑,我们应该在可以使用Unowned的时候尽可能的使用Unowned,具体原因请往下看。
2、Unowned 比Weak的开销更小
Swift 中的每个对象保持了两个引用计数器,一个是强引用计数器,用来决定 ARC 什么时候可以安全地析构这个对象,另外一个附加的弱引用计数器,用来计算创建了多少个指向这个对象的 unowned 或者 weak 引用,当这个计数器为零时,这个对象将被析构 。
弱引用计数器在增加之前(这是一个原子操作),会事先检查一个对象的强引用计数器的值,当值大于0的时候,才确保这是有效的。不然我们访问一个无效的值将会引起程序运行时报错从而导致崩溃。
Unowned 在编译的时候,进行了优化,它不会对有效只进行辨别:如果其引用的对象是一个有效值,它将会顺利在弱引用计数器原本的基础之上加1。如果是一个无效的值,那它将指向一个垃圾内存中的地址,在运行的时候,这将会产生错误,这就是为什么我们需要在使用Unowned时候,要保证对象生命周期的有效性。
Weak针对Unowned 进行了包装(光凭这一点,Unowned 在性能上优于Weak)。Swift 的 weak 引用添加了附加层,间接地把 unowned 引用包裹到了一个可选容器里面,会对可选值进行相应的处理,这将带来一定的开销。所以尽管我们给一个nil对象添加Weak 修饰,程序运行中,依旧不会报错。
这里的性能对比,验证了上面所说的,我们应该在对象的生命周期允许的情况下,尽量使用Unowned 。
_
"_"在swift中有特殊的意义,一般使用来,用于占位进行忽略.
(1)函数参数名忽略;
(2)10_000(跟10000一样,但是加_后更易读)
mutating :
struct 和 class 的差別是 struct 的 function 要去改变 property 的值的时候要加上 mutating,而 class 不用。
throws 、 rethrows
throws 用在函数上, 表示这个函数会抛出错误. 有两种情况会抛出错误, 一种是直接使用 throw 抛出, 另一种是调用其他抛出异常的函数时, 直接使用 try xx 没有处理异常. 如
enum DivideError: Error {
case EqualZeroError;
}
func divide(_ a: Double, _ b: Double) throws -> Double {
guard b != Double(0) else {
throw DivideError.EqualZeroError
}
return a / b
}
func split(pieces: Int) throws -> Double {
return try divide(1, Double(pieces))
}
rethrows 与 throws 类似, 不过只适用于参数中有函数, 且函数会抛出异常的情况, rethrows 可以用 throws 替换, 反过来不行 如
rethrows -> Double {
return try function(a, b)
}
try? 、 try!、try
用于处理可抛出异常的函数。
try需要配合do catch
使用。
try? 、 try!, 使用这两个关键字可以不用写 do catch
.
区别在于, try? 在用于处理可抛出异常函数时, 如果函数抛出异常, 则返回 nil, 否则返回函数返回值的可选值, 如:
print(try? divide(2, 1))
// Optional(2.0)
print(try? divide(2, 0))
// nil
而 try! 则在函数抛出异常的时候崩溃, 否则则返会函数返回值, 相当于(try? xxx)!, 如:
print(try! divide(2, 1))
// 2.0
print(try! divide(2, 0))
// 崩溃
访问控制相关关键字(public等)
open > public > internal > fileprivate > private
open:在其他模块(命名空间)内使用可被访问、继承、重写
public:在其他模块内只能被访问,不能被继承
internal:仅在自身模块中能访问、继承、重写
fileprivate:当前文件内访问
private: 当前作用域内访问