Swift中常用关键字
用作声明的关键字:
let:声明静态变量,类似于const,用let声明的变量不可以再赋值,不然会报错;
var:声明变量,是可以改变值;
class:用来声明一个类;
enum:用来声明一个枚举;
func:用来定义函数
init:相对于类的构造方法的修饰;
deinit:属于析构函数。析构函数(destructor) 与构造函数相反,当对象结束其生命周期时(例如对象所在的函数已调用完毕),系统自动执行析构函数,
和OC中的dealloc 一样的,通常在deinit和dealloc中需要执行的操作有:
- 对象销毁
- KVO移除
- 移除通知
- NSTimer销毁
对于类的构造和释构在swift 中需要使用关键词来修饰,而很多高级语言并不需要特别的指定,如C++ 只需要类名与构造函数名相同就可以,不需要额外的关键词;
extension:扩展,类似于OC的categories,Swift 中的可以扩展以下几个:
- 添加计算型属性和计算静态属性
- 定义实例方法和类型方法
- 提供新的构造器
- 定义下标
- 定义和使用新的嵌套类型
- 使一个已有类型符合某个接口
enum:枚举
import:导入头文件
protocol: 协议,也可以叫接口,这个往往在很多高级语言中不能多重继承的情况下使用协议是一个比较好的多态方式。
static:声明静态变量或者函数
struct: 声明定义一个结构体
subscript:下标索引修饰.可以让class、struct、以及enum使用下标访问内部的值
struct TimesTable {
let multiplier: Int
subscript(index: Int) -> Int {
return multiplier * index
}
}
//TimesTable这个结构中自定义了一个subscript,并且这个subscript类似于方法,看上去它的类型为 Int -> Int。
//然后在调用的时候,就可以使用"[index]"这样的形式取值。
let threeTimesTable = TimesTable(multiplier: 3)
println("six times three is \(threeTimesTable[7])")
extension Array {
subscript(input: [Int]) -> ArraySlice<T> {
get {
var array = ArraySlice<T>()
for i in input {
assert(i < self.count, "index out of range")
array.append(self[i])
}
return array
}
set {
// i表示数组input自己的索引,index表示数组self的索引
for (i, index) in enumerate(input) {
assert(index < self.count, "index out of range")
self[index] = newValue[i]
}
}
}
}
typealias:为此类型声明一个别名.和 typedef类似.
override:如果我们要重写某个方法, 或者某个属性的话, 我们需要在重写的变量前增加一个override关键字, 比如:
class Fruit {
var sellPrice : Double = 0
func info() -> () {
print("fruit")
}
//修饰词 final 表示 不可重写 可以将类或者类中的部分实现保护起来,从而避免子类破坏
final func price(){
print("price")
}
}
class Apple : Fruit {//类继承
func eat () -> () {
print("apple22222")
}
//重写父类方法
override func info() {
print("重写父类的info 方法00000")
}
//重写父类的属性 重写父类的属性或者方法要使用关键字 override 进行修饰
override var sellPrice: Double {
get {
print("kkkkkkk\(super.sellPrice)")
return super.sellPrice + 3
}
set {
print("qqqqq")
super.sellPrice = newValue * newValue
}
}
}
let app = Apple()
app.info()
app.sellPrice = 20.0
let adb = app.sellPrice
print("adb == \(adb)")
/**
输出结果为:
重写父类的info 方法00000
qqqqq
kkkkkkk400.0
adb == 403.0
*/
final:Swift中,final关键字可以在class、func和var前修饰。表示 不可重写,可以将类或者类中的部分实现保护起来,从而避免子类破坏。详细了解可以去看看(Swift - final关键字的介绍,以及使用场景)
class Fruit {
//修饰词 final 表示 不可重写 可以将类或者类中的部分实现保护起来,从而避免子类破坏
final func price(){
print("price")
}
}
class Apple : Fruit {//类继承
//重写父类方法
override func price() {
print("重写父类的price 方法")
}
// 上面的会报错
}
用作语句的关键字
break:跳出循环.一般在控制流中使用,比如 for . while switch等语句
case:switch的选择分支.
continue: 跳过本次循环,继续执行后面的循环.
in:范围或集合操作,多用于遍历.
fallthrough: swift语言特性switch语句的break可以忽略不写,满足条件时直接跳出循环.fallthrough的作用就是执行完当前case,继续执行下面的case.类似于其它语言中省去break里,会继续往后一个case跑,直到碰到break或default才完成的效果.
switch integerToDescribe {
case 1, 3, 5, 7, 11, 13, 17, 19:
description += " a prime number, and also";
fallthrough // 执行到此并不跳出循环,而是继续执行case5
case 5:
description += " an integer" // 执行到这一步,跳出循环
default :
description += " finished"
}
where:用于条件判断,和数据库查询时的where 'id > 10'这样功能. swift语言的特性.OC中并没有.
let yetAnotherPoint = (1, -1)
switch yetAnotherPoint {
case let (x, y) where x == y:
println("(\\(x), \\(y)) is on the line x == y")
case let (x, y) where x == -y:
println("(\\(x), \\(y)) is on the line x == -y")
case let (x, y):
println("(\\(x), \\(y)) is just some arbitrary point")
当switch的条件满足where 后面的条件时,才执行语句。
用作表达和类型的关键字
is:is一般用于对一些变量的类型做判断.类似于OC中的isKindClass. as 与强制转换含义雷同.
for view : AnyObject in self.view.subviews
{
if view is UIButton
{
let btn = view as UIButton;
println(btn)
}
}
as:keyword:Guaranteed conversion、 Upcasting
理解:字面理解就是有保证的转换,从派生类转换为基类的向上转型
// 将1转成float
let num = 1 as CGFloat
// dog转换到父类animal
class Animal {}
class Dog: Animal {}
let d = Dog()
d as Animal
!as:keyword:Forced conversion、 Downcasting
理解:字面理解就是有强项转换,即向下转型,子类(派生类)向父类转换,官方解释说这是一个不被保证的转换,可能会因为强转的失败而会导致崩溃。同时 !是一个陷阱的标志,就像⚠️一样,用起来存在一定危险性
// Dog到Animal的转化
class Animal {}
class Dog: Animal {}
let a: Animal = Dog()
a as Dog // as不能将a转成Dog,即不能向下转换
a as! Dog // as!能强行将a转成Dog -> Bingo
as?keyword:** Optional、 Nil***
Swfit代码写一段时间后会发现到处都是 ?,这预示着如果转换不成功的时候便会返回一个 nil 对象,成功的话返回可选类型值(optional)。
// Dog、Cat和Animal的转换关系
class Animal {}
class Cat: Animal {}
class Dog: Animal {
var name = "Spot"
}
let dog: Dog? = nil
dog?.name // 选择调用,返回空值nil
dog!.name // 强行调用,报错
let animal: Animal = Cat()
animal as? Dog // 猫转狗失败,返回nil
animal as! Dog // 猫强行转狗,失败报错
dynamicType : 获取对象的动态类型,即运行时的实际类型,而非代码指定或编译器看到的类型
#column: 列号,
#file:路径,
#function: 函数,
#line : 行号
print("COLUMN = (#column) \n FILE = (#file) \n FUNCTION = (#function) \n LINE = (#line)")
特定上下文中被保留的关键字:
associativity:运算符的结合性
get、set:
当我们得到属性值的时候,会调用该属性的get方法。
当我们去设置属性值的时候,会调用该属性的set方法。
当我们给属性设置值的时候,Swift会自动给我们创建一个名为newValue的常量并且可以用于set{}中。
Swift中有储值属性和计算属性,一般我们应该是给计算属性添加get和set方法,先通过一个Example展示:
var A:Int = 0
var B:Int = 0
var C:Int {
get {
return 1
}
set {
print("Recived new value", newValue, " and stored into 'B' ")
B = newValue
}
}
//When we are getting a value of C it fires get{} part of C property
A = C
A //Now A = 1
//When we are setting a value to C it fires set{} part of C property
C = 2
B //B = 2
//定义一个变量
var _tittle: String?
var tittle: String? {
set {
_tittle=newValue
}
get {
return _tittle
}
}
tittle = "跳跳"
print("title: \(tittle ?? "tiaotiao")")
// tittle:跳跳
willSet、didset:在Swift语言中用了willSet和didSet这两个特性来监视属性的除初始化之外的属性值变化
下面例子很好说明:
class People : NSObject
{
//普通属性
var firstName:String = ""
var lastName:String = ""
var nickName:String = ""
//计算属性
var fullName:String
{
get
{
return nickName + " " + firstName + " " + lastName
}
}
//带属性监视器的普通属性
var age:Int = 0
{
//我们需要在age属性变化前做点什么
willSet
{
print("Will set an new value \(newValue) to age")
}
//我们需要在age属性发生变化后,更新一下nickName这个属性
didSet
{
print("age filed changed form \(oldValue) to \(age)")
if age<10
{
nickName = "Little"
}else
{
nickName = "Big"
}
}
}
func toString() -> String
{
return "Full Name: \(fullName) " + ", Age: \(age) "
}
}
// 调用
var me = People()
me.firstName = "Zhang"
me.lastName = "San"
me.age = 20
print(me.toString())
/*程序输出
Will set an new value 20 to age
age filed changed form 0 to 20
Full Name: Big Zhang San , Age: 20
*/
infix:表示要定义的是一个中位操作符,即前后都是输入
inout:inout作为函数声明时,引用传值的关键字。但是在调用的时候引用的是地址,所以在引用的时候要加上&
func test( a :inout Int , i :inout Int) {
// 函数内相关操作
}
var num1 = 3
var num2 = 10
test(a: &num1,i: &num2)
left:可用于拓展的约束属性
mutating:写在func前面,以便于让func可以修改struct和protocol的extension中的成员的值。 如果func前面不加mutating,struct和protocol的extension中的成员的值便被保护起来,不能修改
none
nonmutating:一般配合set使用。如
protocol Settings {
subscript(key: String) -> AnyObject? { get nonmutating set }
}
struct testT {
let b: Int {
get {
return 3
}
set {
print("\(newValue)")
}
}
}
//上面代码会报错
//一种做法是声明成var,想怎么改,就怎么改。
//另一种做法就是nonmutating,它告诉编译器不会修改实例内部的值,也就是set时,不会改变任何其他的变量。
struct Test2 {
var b: Int {
get {
return 2
}
nonmutating set {
print("\(newValue)")
}
}
}
let t = Test2()
t.b = 3
print(t.b)
// 3 2
operator、postfix:在Swift中定义属于自己的运算符
var foo: String?
//定义这个样一个类型,在没有赋值的情况下使用它
let bar = foo!
//这样绝对会崩溃,因为它是`nil`啊,强制解包绝对傻了。所以我定义了运算符,省的判断:
let bar = foo~~
//这样,如果它是空,就返回`""`(空字符串)
postfix operator ~~
postfix func ~~(v: String?) -> String {
return v == nil ? "" : v!
}
这里需要考虑的是,运算符都是放在右边的吗?
那怎么定义一个运算符在左边还是右边起作用?
重点在 postfix
- 左(前缀):
prefix
- 右(后缀):
postfix
- 中(中缀):
infix
postfix operator ~~ {}
postfix func ~~(a: String?) -> String { return a == nil ? "" : a! }
postfix func ~~(a: Int?) -> Int { return a == nil ? 0 : a! }
postfix func ~~(a: Int8?) -> Int8 { return a == nil ? 0 : a!}
postfix func ~~(a: Int16?) -> Int16 { return a == nil ? 0 : a! }
postfix func ~~(a: Int32?) -> Int32 { return a == nil ? 0 : a! }
postfix func ~~(a: Int64?) -> Int64 { return a == nil ? 0 : a! }
postfix func ~~(a: UInt?) -> UInt { return a == nil ? 0 : a! }
postfix func ~~(a: Double?) -> Double { return a == nil ? 0 : a! }
postfix func ~~(a: Float?) -> Float { return a == nil ? 0 : a! }
postfix func ~~(a: [AnyObject]?) -> [AnyObject] { return a == nil ? [] : a! }
postfix func ~~(a: [String]?) -> [String] { return a == nil ? [] : a! }
postfix func ~~(a: [Int]?) -> [Int] { return a == nil ? [] : a! }
postfix func ~~(a: [String: AnyObject]?) -> [String: AnyObject] { return a == nil ? [:] : a! }
postfix func ~~(a: [String: String]?) -> [String: String] { return a == nil ? [:] : a! }
infix operator += {
associativity right //结合性,右结合
precedence 90 //优先级,90
}
infix operator * {
associativity left
precedence 150
}
infix operator - {
associativity left
precedence 140
}
infix operator + {
associativity left
precedence 140
}
- left
- right
- none 默认
precedence(优先级):
- 0~255 可选范围
- 100 默认
precedence:运算的优先级,越高的话优先进行计算。swift 中乘法和除法的优先级是 150 ,加法和减法的优先级是 140 ,这里我们定义点积的优先级为 160 ,就是说应该早于普通的乘除进行运算。
rightset
unowned、unowned(sale)、unowned(unsafe):无宿主引用
与弱引用一样,当把一个实例声明为无主引用时,此实例不会持有这个对象,即不会使对象的引用计数加1。但与弱引用不同的是,当对象被废弃,其无主引用并不会被置为 nil。
在Swift中,写下 unowned 相当于 unowned(safe)。但在官方文档中提到, Swift 还提供了另一种不安全的无主引用 unowned(unsafe) 来禁用运行时的安全检查。运行时的安全检查就是使 unowned(safe) 安全的原因。
unowned(safe):当访问 unowned(safe) 类型的无主引用时,运行时会进行安全检查,如果对象已经废弃,将抛出异常并终止程序。
unowned(unsafe) :unowned(unsafe) 的作用效果实际上相当于 Objective-C 属性标示符中的 assign/unsafeunretained。访问 unowned(unsafe) 类型的无主引用时,运行时的安全检查被禁用,这时会有三种情况:
-
废弃对象内存还未被覆盖:程序正常运行
-
废弃对象内存被部分覆盖:奇怪的 crash,不确定的结果
-
废弃对象内存正好填入新的对象:由于向新的对象发送了调用旧对象方法的消息,会出现 unrecognized selector exceptions
weak:weak 即弱引用,当把一个实例声明为弱引用时,此实例不会持有这个对象,即不会使对象的引用计数加1。当对象被废弃,其所有的弱引用会被置为 nil。这样保证了当你调用一个弱引用对象时,你能得到一个对象或者nil.
weak 引用并不能保护所引用的对象被ARC机制销毁。强引用能使被引用对象的引用计数+1,而弱引用不会。
往往在闭包使用 weak 和 unowned 变量,你应该用[]把它们括起来。如:
let closure = { [weak self] in
self?.doSomething() //Remember, all weak variables are Optionals!
}
为什么要把 weak self 要放在方括号内?在Swift中,我们看到方括号就会想到数组。你猜怎么着?你可以在在闭包内定义多个捕获值!例如:
let closure = { [weak self, unowned customInstance] in //Look at that sweet Array of capture values.
self?.doSomething() //weak variables are Optionals!
customInstance.Dosomething() //unowned variables are not.
}
willset、didSet:willSet 和 didSet的作用是对赋值过程前后附加额外的操作,可以看做是捕获状态然后做操作,在将要赋值的时候和已经赋值的时候做相关操作
convenience:convenience用来进行方便的初始化,就相当于构造函数重载。
对于class来讲,默认或指定的初始化方法作为所谓的Designated初始化。
若重载的初始化需要调用Designated初始化则将它作为convenience初始化,在方法前要加上convenience关键字。
class Figure{
var name:String!
var nikname:String?
init(){
name = "John"
}
convenience init(name:String!,nikname:String!) {
self.init()
self.name = name
self.nikname = nikname
}
}
defer:用来包裹一段代码,这个代码块将会在当前作用域结束的时候被调用。这通常被用来对当前的代码进行一些清理工作,比如关闭打开的文件等。
可以在同一个作用域中指定多个 defer代码块,在当前作用域结束时,它们会以相反的顺序被调用,即先定义的后执行,后定义的先执行。
guard : 当某些条件不满足的情况下,跳出作用域.
func testFunc(input:Int) {
guard input < 10 else {
print("Input must < 10")
return
}
print("Input is \(input)")
}
testFunc(input: 1)
testFunc(input: 11)
与if用法一样,但是作用与if相反。
相比if来说,guard有一个好处:如果不使用return,break,continue,throw跳出当前作用域,编译器会报错.所以,对那些对条件要求十分严格的地方,guard是不二之选。
guard也可以使用可选绑定(Optional Binding)也就是 guard let
的格式
func testMathFunc(input:Int?){
guard let _ = input else {
print("Input cannot be nil")
return
}
}
testMathFunc(input: nil)
??:空合运算符,这个我偷懒了下😝,这里生动的阐述了这个小东东
组合
class var: 在swift中对于enum和struct来说支持用static关键字来标示静态变量,但是对于class成员来说,只能以class var的方式返回一个只读值。例如:
struct SomeStructure {
static var storedTypeProperty = "Some value."
static var computedTypeProperty: Int {
// return an Int value here
return 5;
}
}
enum SomeEnumeration {
static var storedTypeProperty = "Some value."
static var computedTypeProperty: Int {
// return an Int value here
return 5;
}
}
class SomeClass {
class var computedTypeProperty: Int {
return 5;
}
}
这样其实很好的区分了struct和class的功能,不像C# 抓来一个随便用,但相对于oc来讲其实是弱化了界限,
如果你想在class中搞一个非只读的静态变量出来,可以和struct进行配合。