Swift 基本语法2
Posted fearlessyyp
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Swift 基本语法2相关的知识,希望对你有一定的参考价值。
一、?和!
1、可选类型: ?
在swift中,可选类型(?)其根源是一个枚举型,里面有None和Some两种类型。其实所谓的nil就是Optional.None, 非nil就是Optional.Some.
! 代表强制解包
1 // MARK: - ?和! 2 // ?代表可选类型,实际上的值是枚举类型 -- None和Some,其实nil值相当于Optional.None,非nil就是Optional.Some 3 // !代表强制解包 4 5 // 定义一个Int类型的可选类型变量 6 var num : Int? = 8 7 // 把这个类型类型的变量赋值给另一个可选类型的变量 8 var num1 = num 9 print(num1) 10 // 打印出来以后是一个Optional类型的值,如果要取到8,必须对可选类型强制解包! 11 var num2 = num! 12 print(num1) 13 14 var number : Int? 15 // 如果对没值(nil)的变量进行强制解包,会造成程序崩溃 16 //var number1 = number!
2、可选绑定
可选类型分为有值和没值,如果可选类型的变量没值时对其强制解包,程序就会崩溃 。所以,强制解包是非常危险的
1 var number : Int? 2 // 如果对没值(nil)的变量进行强制解包,会造成程序崩溃 3 //var number1 = number! 4 5 // 可选绑定 6 // 如果不确定可选类型变量是否有值时,用可选绑定,不需要对可选类型强制解包 7 if var number2 = number { 8 print(number2) 9 }
3、隐式解析可选类型
隐式解析可选类型和可选类型一样,都是有值和没值(nil)两种结果,区别是赋值时,隐式解析可选类型不需要强制解包。
1 // 隐式解析可选类型:有值,没值(nil) 2 3 var intNum : Int! = 3 4 var intNum1 = intNum 5 print(intNum) 6 print(intNum1) 7 8 // 如果隐式解析可选类型的变量没值,程序一样会崩溃 9 10 var intNumber :Int! 11 //var intNumber1 = intNumber 12 //print(intNumber1) 13 14 // 可选绑定 15 if var intNumber2 = intNumber { 16 print(intNumber2) 17 }
二、结构体
Swift的结构体对比OC来说,可以添加初始化方法、可以遵守代理协议等
声明一个结构体的格式:
struct 结构体的名字 {
声明成员变量等
}
计算属性与存储属性
· 存储属性就是类或结构体里定义的变量(或常量)。存储属性可以是变量存储属性(用关键字 var定义),也可以是常量存储属性(用关键字let定义)。
· 除存储属性外,类、结构体和枚举可以定义计算属性。计算属性不直接存储值,而是提供一个必写的getter和一个可选的setter来间接获取和设置其他属性或变量的值。不可以在计算属性中使用self.否则会造成死循环。
1 // MARK: - 结构体 2 // 声明一个结构体 3 struct Rect { 4 // 声明结构体变量的属性(存储属性) 5 // 注意,结构体变量中的属性类型可以使用let去修饰,只不过访问的时候不能对其值进行修改 6 var x : Float 7 var y : Float 8 let width : Float 9 var height : Float 10 // 声明结构体属性,要使用static 11 static var description : String? 12 // 声明一个计算属性(是用来专门计算结构体变量属性的setter方法和getter方法,其本身并没有存储功能) 13 var centerX : Float { 14 // setter方法(可以不写setter) 15 set { 16 x = newValue // newValue是外界调用方法时传进来的参数 17 } 18 // getter方法(必须要写getter) 19 get { 20 return x / 2 21 } 22 } 23 24 var centerY :Float { 25 get { 26 return y / 2 27 } 28 } 29 30 // 声明方法 31 // 声明结构体变量方法/成员方法(相当于OC中的实例方法) 32 func frameInfor() { 33 print("x:\(x), y:\(y), width:\(width), height:\(height)") 34 } 35 // 声明结构体方法(相当于OC中的类方法),使用static修饰 36 static func infor() { 37 print("这是结构体方法") 38 } 39 } 40 41 // 1、根据结构体去定义一个结构体变量,结构体有自带的构造方法 42 var frame = Rect(x: 345, y: 22, width: 42, height: 64) 43 // 2、访问结构体变量中的属性, 用结构体变量去访问 44 frame.height = 22 45 print(frame.height) 46 47 // 3、访问结构体属性,用结构体去访问 48 Rect.description = "是" 49 print(Rect.description) 50 51 // 4、访问计算属性 52 frame.centerX = 100 // 调用了setter方法 53 print(frame.centerX) // 调用了getter方法 54 55 // 5、调用结构体变量方法 56 frame.frameInfor() 57 58 // 6、调用结构体方法 59 Rect.infor()
结构体遵守代理协议(经自己验证,协议中声明的方法只能是计算属性,否则不能遵守)
1 // 7、结构体遵守代理协议 2 3 protocol Named { 4 var name: String { get } 5 } 6 protocol Aged { 7 var age: Int { get } 8 } 9 struct Person: Named, Aged { 10 var name: String 11 var age: Int 12 }
三、类
类是人们构建代码所用的一种通用且灵活的构造体。我们可以使用与结构体完全相同的语法规则来为类定义属性(常量、变量)和添加方法。
我们通过关键字class来定义类,并在一对大括号中定义它们的具体内容:
class ClassName {
类的内部细节
}
声明类方法的方式有两种
使用 static 和 class 都可以修饰类方法,区别在于:class修饰的类方法可以被子类重写;static修饰的类方法不可以被子类重写,防止父类方法被修改
1 // MARK: - 类(class) 2 class Person { 3 // 属性 4 var name : String? 5 var age : Int? 6 7 // 初始化方法 8 init(name : String, age : Int) { 9 self.name = name 10 self.age = age 11 } 12 13 // 声明类属性 14 static var introduce : String? 15 16 // 声明计算属性(setter,getter, 不能用self. 否则会造成死循环) 17 var value : Int { 18 set { 19 age = newValue // newValue是外界调用方法时从外界传进来的参数 20 } 21 get { 22 return age! 23 } 24 } 25 26 // 声明类方法,在类方法中只能使用类属性,不能使用对象属性 27 // 1、用static关键字修饰,虽然是一个类方法,但是该方法在子类中不能重写 28 static func sayHi() { 29 print(introduce! + "hi") 30 } 31 // 2、用class关键字修饰,可以被子类重写 32 class func sayHello() { 33 print(introduce! + "hello") 34 } 35 36 // 声明实例方法 37 func sayBey() { 38 print("BeyBey"); 39 } 40 } 41 42 // 1、创建对象,调用初始化方法 43 var per : Person = Person(name : "MBBoy", age : 12) 44 print(per.name! + "\(per.age!)") 45 46 // 2、访问类属性 47 Person.introduce = "我是XXX" 48 print(Person.introduce!) 49 50 // 3、访问计算属性 51 per.value = 20; 52 print(per.value) 53 54 // 4、访问类方法 55 Person.sayHello() 56 Person.sayHi() 57 58 // 5、访问实例方法 59 per.sayBey() 60 61 // 定义一个Person类的子类Student,Swift不支持多继承 62 class Student : Person { 63 // 重写父类中的类方法 64 override class func sayHello() { 65 print("子类Student中重写的类方法sayHello") 66 } 67 68 // 重写父类中的实例方法 69 override func sayBey() { 70 print("子类Student中重写的实例方法sayBey") 71 } 72 } 73 74 // 1、初始化Student类的对象 75 var student : Student = Student(name: "yyp", age: 11) 76 Student.sayHi() 77 78 // 2、调用重写的父类中的类方法 79 Student.sayHello() 80 81 // 3、调用重写的父类中的实例方法 82 student.sayBey()
值类型与引用类型
- 值类型:
值类型(Value Types):每个实例都保留了一分独有的数据拷贝,一般以结构体 (struct)、枚举(enum) 或者元组(tuple)的形式出现。
- 引用类型:
引用类型(Reference Type):每个实例共享同一份数据来源(在native层面说的话,就是该类型的每个实例都指向内存中的同一个地址),一般以类(class)的形式出现。
- 值类型与引用类型使用情形
- 使用值类型的情形:
使用==运算符比较实例数据的时候。
你想单独复制一份实例数据的时候。
当在多线程环境下操作数据的时候。 - 使用引用类型(比如class)的情形:
当使用===运算符判断两个对象是否引用同一个对象实例的时候。
当上下文需要创建一个共享的、可变的对象时。
- 使用值类型的情形:
- 值类型与引用类型的区别:
值类型和引用类型最基本的分别在复制之后的结果。- 当一个值类型被复制的时候,相当于创造了一个完全独立的实例,这个实例保有属于自己的独有数据,数据不会受到其他实例的数据变化影响。
- 复制一个引用类型的时候,实际上是默默地创造了一个共享的实例分身,两者是共用一套数据。因此修改其中任何一个实例的数据,也会影响到另外那个。
1 // MARK: - 值类型和引用值类型 2 // 值类型 3 struct animal { 4 var name : String? 5 var age : Int? 6 7 init(name : String, age : Int) { 8 self.name = name 9 self.age = age 10 } 11 } 12 13 var dog : animal = animal(name: "阿福", age: 3) 14 // 将dog变量的值赋给dog1(其实是一个拷贝的过程) 15 var dog1 = dog 16 dog.name = "aFu" 17 print(dog.name) // 打印结果:aFu 18 print(dog1.name) // 打印结果:阿福 19 20 // 引用值类型 21 class pet { 22 var name : String? 23 var age : Int? 24 25 init(name : String, age : Int) { 26 self.name = name 27 self.age = age 28 } 29 } 30 31 var cat : pet = pet(name: "懵", age: 2) 32 // 将cat变量的值赋给cat1(其实是一个引用的过程) 33 var cat1 = cat 34 cat.name = "萌" 35 print(cat.name) // 打印结果:萌 36 print(cat1.name) // 打印结果:萌
四、协议(protocol)
· 协议定义了一个蓝图,规定了用来实现某一特定工作或者功能所必需的方法和属性
· 类,结构体或枚举类型都可以遵循协议,并提供具体实现来完成协议定义的方法和功能
· 任意能够满足协议要求的类型被称为遵循(conform)这个协议
声明一个带有可选函数的协议时,必须用@objc来修饰,可选函数要用optional关键字修饰
类遵守协议时,直接在本类后面的冒号的后面,使用","号分隔;或者写在父类名后面,使用","号分隔
必须实现的协议方法,就必须实现,否则会报错
直接实现可选协议里的方法,会报警告,可以添加 @objc 或者继承NSObjec
1 // MARK: - 协议(protocol) 2 // 在Swift中声明协议的时候,协议里有可选方法时,需要使用@objc关键字修饰 3 4 // 结婚协议 5 @objc protocol MarryProtocol { 6 func cook() // 做饭 7 func wash() // 洗衣服 8 optional func hitDouDou() // 打豆豆,可选方法 9 } 10 11 // 离婚协议 12 protocol DivorceProtocol { 13 func DivideMoney() // 分财产 14 } 15 16 // 继承与Person,实现了MarryProtocol协议和DivorceProtocol协议 17 // 如果该类是另一个类的子类,先写父类,再写遵循的协议 18 class Man : Person, MarryProtocol, DivorceProtocol { 19 @objc func cook() { 20 print("还好去新东方学了几年的厨艺,终于可以大展身手") 21 } 22 @objc func wash() { 23 print("还好买了台洗衣机") 24 } 25 26 func DivideMoney() { 27 print("分财产") 28 } 29 } 30 31 // 创建一个男人 32 var man = Man(name: "韦小宝", age: 22) 33 man.cook() 34 man.wash() 35 man.DivideMoney()
五、扩展(Extension)
· extension + 类名(结构体名字)可以对一个类和结构体扩展方法
· extension可以多次对一个类进行扩展,也可以给一个类扩展协议方法
· 扩展只能增加方法,不能增加属性
// MARK: - 扩展(Extension) // 1、扩展协议中的相关方法 extension Man { @objc func hitDouDou() { print("打豆豆") } } man.hitDouDou() // 2、扩展类方法以及对象方法 (类似于OC的类目(Category)) extension Man { // 对象方法 func sing() { print("唱歌") } // 类方法 class func dance() { print("growl") } } man.sing() Man.dance()
六、闭包
· 闭包是自包含的函数代码块,可以在代码中被传递和使用。 Swift 中的闭包与 C 和 Objective-C 中的代码块(block)以及其他一些编程语言中的匿名函数比较相似。
· 闭包可以捕获和存储其所在上下文中任意常量和变量的引用。 这就是所谓的闭合并包裹着这些常量和变量,俗称闭包。Swift 会为您管理在捕获过程中涉及到的所有内存操作。
1.语法形式
{(参数)-> 返回值类型 in
执行语句
}
注意:闭包的函数体部分由关键字 in 引入。 该关键字表示闭包的参数和返回值类型定义已经完成,闭包函数体即将开始。
1 // MARK: - 闭包 2 // 求两个数的最大值 3 /* 4 在OC中使用Block实现 5 int (^block)(int a, int, b) = ^int (int a, int b) { 6 return a > b ? a : b; 7 } 8 */ 9 10 // 使用闭包 11 var myBlock : ((a : Int, b : Int) -> Int) 12 13 // 第一种方式 14 myBlock = { 15 (a : Int, b : Int) -> Int in 16 return a > b ? a : b 17 } 18 19 // 第二种方式 20 myBlock = { 21 (a, b) -> Int in 22 return a > b ? a : b 23 } 24 25 // 第三种方式 26 myBlock = { 27 a, b in 28 return a > b ? a : b 29 } 30 31 // 第四种方式 32 myBlock = { 33 a, b in 34 // 不用return关键字 35 a > b ? a : b 36 } 37 38 // 第五种方式 39 myBlock = { 40 a, b in 41 return a > b ? a : b 42 } 43 44 let max = myBlock(a: 3, b: 6) 45 print(max)
以上是关于Swift 基本语法2的主要内容,如果未能解决你的问题,请参考以下文章