Swift 基本语法2

时间:2021-03-30 14:35:39

一、?和!

1、可选类型: ?

在swift中,可选类型(?)其根源是一个枚举型,里面有None和Some两种类型。其实所谓的nil就是Optional.None, 非nil就是Optional.Some.

! 代表强制解包

 // MARK: - ?和!
// ?代表可选类型,实际上的值是枚举类型 -- None和Some,其实nil值相当于Optional.None,非nil就是Optional.Some
// !代表强制解包 // 定义一个Int类型的可选类型变量
var num : Int? =
// 把这个类型类型的变量赋值给另一个可选类型的变量
var num1 = num
print(num1)
// 打印出来以后是一个Optional类型的值,如果要取到8,必须对可选类型强制解包!
var num2 = num!
print(num2) var number : Int?
// 如果对没值(nil)的变量进行强制解包,会造成程序崩溃
//var number1 = number!

2、可选绑定

可选类型分为有值和没值,如果可选类型的变量没值时对其强制解包,程序就会崩溃 。所以,强制解包是非常危险的

 var number : Int?
// 如果对没值(nil)的变量进行强制解包,会造成程序崩溃
//var number1 = number! // 可选绑定
// 如果不确定可选类型变量是否有值时,用可选绑定,不需要对可选类型强制解包
if var number2 = number {
print(number2)
}

3、隐式解析可选类型

隐式解析可选类型和可选类型一样,都是有值和没值(nil)两种结果,区别是赋值时,隐式解析可选类型不需要强制解包。

 // 隐式解析可选类型:有值,没值(nil)

 var intNum : Int! =
var intNum1 = intNum
print(intNum)
print(intNum1) // 如果隐式解析可选类型的变量没值,程序一样会崩溃 var intNumber :Int!
//var intNumber1 = intNumber
//print(intNumber1) // 可选绑定
if var intNumber2 = intNumber {
print(intNumber2)
}

二、结构体

Swift的结构体对比OC来说,可以添加初始化方法、可以遵守代理协议等

声明一个结构体的格式:
struct 结构体的名字 {
   声明成员变量等

计算属性与存储属性

· 存储属性就是类或结构体里定义的变量(或常量)。存储属性可以是变量存储属性(用关键字 var定义),也可以是常量存储属性(用关键字let定义)。
· 除存储属性外,类、结构体和枚举可以定义计算属性。计算属性不直接存储值,而是提供一个必写的getter和一个可选的setter来间接获取和设置其他属性或变量的值。不可以在计算属性中使用self.否则会造成死循环。

 // MARK: - 结构体
// 声明一个结构体
struct Rect {
// 声明结构体变量的属性(存储属性)
// 注意,结构体变量中的属性类型可以使用let去修饰,只不过访问的时候不能对其值进行修改
var x : Float
var y : Float
let width : Float
var height : Float
// 声明结构体属性,要使用static
static var description : String?
// 声明一个计算属性(是用来专门计算结构体变量属性的setter方法和getter方法,其本身并没有存储功能)
var centerX : Float {
// setter方法(可以不写setter)
set {
x = newValue // newValue是外界调用方法时传进来的参数
}
// getter方法(必须要写getter)
get {
return x /
}
} var centerY :Float {
get {
return y /
}
} // 声明方法
// 声明结构体变量方法/成员方法(相当于OC中的实例方法)
func frameInfor() {
print("x:\(x), y:\(y), width:\(width), height:\(height)")
}
// 声明结构体方法(相当于OC中的类方法),使用static修饰
static func infor() {
print("这是结构体方法")
}
} // 1、根据结构体去定义一个结构体变量,结构体有自带的构造方法
var frame = Rect(x: , y: , width: , height: )
// 2、访问结构体变量中的属性, 用结构体变量去访问
frame.height =
print(frame.height) // 3、访问结构体属性,用结构体去访问
Rect.description = "是"
print(Rect.description) // 4、访问计算属性
frame.centerX = // 调用了setter方法
print(frame.centerX) // 调用了getter方法 // 5、调用结构体变量方法
frame.frameInfor() // 6、调用结构体方法
Rect.infor()

结构体遵守代理协议(经自己验证,协议中声明的方法只能是计算属性,否则不能遵守)

 // 7、结构体遵守代理协议

 protocol Named {
var name: String { get }
}
protocol Aged {
var age: Int { get }
}
struct Person: Named, Aged {
var name: String
var age: Int
}

三、类

类是人们构建代码所用的一种通用且灵活的构造体。我们可以使用与结构体完全相同的语法规则来为类定义属性(常量、变量)和添加方法。

我们通过关键字class来定义类,并在一对大括号中定义它们的具体内容:
class ClassName {
  类的内部细节
}

声明类方法的方式有两种

使用 static 和 class 都可以修饰类方法,区别在于:class修饰的类方法可以被子类重写;static修饰的类方法不可以被子类重写,防止父类方法被修改

 // MARK: - 类(class)
class Person {
// 属性
var name : String?
var age : Int? // 初始化方法
init(name : String, age : Int) {
self.name = name
self.age = age
} // 声明类属性
static var introduce : String? // 声明计算属性(setter,getter, 不能用self. 否则会造成死循环)
var value : Int {
set {
age = newValue // newValue是外界调用方法时从外界传进来的参数
}
get {
return age!
}
} // 声明类方法,在类方法中只能使用类属性,不能使用对象属性
// 1、用static关键字修饰,虽然是一个类方法,但是该方法在子类中不能重写
static func sayHi() {
print(introduce! + "hi")
}
// 2、用class关键字修饰,可以被子类重写
class func sayHello() {
print(introduce! + "hello")
} // 声明实例方法
func sayBey() {
print("BeyBey");
}
} // 1、创建对象,调用初始化方法
var per : Person = Person(name : "MBBoy", age : )
print(per.name! + "\(per.age!)") // 2、访问类属性
Person.introduce = "我是XXX"
print(Person.introduce!) // 3、访问计算属性
per.value = ;
print(per.value) // 4、访问类方法
Person.sayHello()
Person.sayHi() // 5、访问实例方法
per.sayBey() // 定义一个Person类的子类Student,Swift不支持多继承
class Student : Person {
// 重写父类中的类方法
override class func sayHello() {
print("子类Student中重写的类方法sayHello")
} // 重写父类中的实例方法
override func sayBey() {
print("子类Student中重写的实例方法sayBey")
}
} // 1、初始化Student类的对象
var student : Student = Student(name: "yyp", age: )
Student.sayHi() // 2、调用重写的父类中的类方法
Student.sayHello() // 3、调用重写的父类中的实例方法
student.sayBey()

值类型与引用类型

  • 值类型:

    值类型(Value Types):每个实例都保留了一分独有的数据拷贝,一般以结构体 (struct)、枚举(enum) 或者元组(tuple)的形式出现。

  • 引用类型:

    引用类型(Reference Type):每个实例共享同一份数据来源(在native层面说的话,就是该类型的每个实例都指向内存中的同一个地址),一般以类(class)的形式出现。

  • 值类型与引用类型使用情形
    • 使用值类型的情形:
              使用==运算符比较实例数据的时候。
              你想单独复制一份实例数据的时候。
              当在多线程环境下操作数据的时候。
    • 使用引用类型(比如class)的情形:
              当使用===运算符判断两个对象是否引用同一个对象实例的时候。
              当上下文需要创建一个共享的、可变的对象时。
  • 值类型与引用类型的区别:
    值类型和引用类型最基本的分别在复制之后的结果。
    • 当一个值类型被复制的时候,相当于创造了一个完全独立的实例,这个实例保有属于自己的独有数据,数据不会受到其他实例的数据变化影响。
    • 复制一个引用类型的时候,实际上是默默地创造了一个共享的实例分身,两者是共用一套数据。因此修改其中任何一个实例的数据,也会影响到另外那个。
 // MARK: - 值类型和引用值类型
// 值类型
struct animal {
var name : String?
var age : Int? init(name : String, age : Int) {
self.name = name
self.age = age
}
} var dog : animal = animal(name: "阿福", age: )
// 将dog变量的值赋给dog1(其实是一个拷贝的过程)
var dog1 = dog
dog.name = "aFu"
print(dog.name) // 打印结果:aFu
print(dog1.name) // 打印结果:阿福 // 引用值类型
class pet {
var name : String?
var age : Int? init(name : String, age : Int) {
self.name = name
self.age = age
}
} var cat : pet = pet(name: "懵", age: )
// 将cat变量的值赋给cat1(其实是一个引用的过程)
var cat1 = cat
cat.name = "萌"
print(cat.name) // 打印结果:萌
print(cat1.name) // 打印结果:萌

四、协议(protocol)

·  协议定义了一个蓝图,规定了用来实现某一特定工作或者功能所必需的方法和属性
·  类,结构体或枚举类型都可以遵循协议,并提供具体实现来完成协议定义的方法和功能
·  任意能够满足协议要求的类型被称为遵循(conform)这个协议

声明一个带有可选函数的协议时,必须用@objc来修饰,可选函数要用optional关键字修饰

类遵守协议时,直接在本类后面的冒号的后面,使用","号分隔;或者写在父类名后面,使用","号分隔

必须实现的协议方法,就必须实现,否则会报错

直接实现可选协议里的方法,会报警告,可以添加 @objc 或者继承NSObjec

 // MARK: - 协议(protocol)
// 在Swift中声明协议的时候,协议里有可选方法时,需要使用@objc关键字修饰 // 结婚协议
@objc protocol MarryProtocol {
func cook() // 做饭
func wash() // 洗衣服
optional func hitDouDou() // 打豆豆,可选方法
} // 离婚协议
protocol DivorceProtocol {
func DivideMoney() // 分财产
} // 继承与Person,实现了MarryProtocol协议和DivorceProtocol协议
// 如果该类是另一个类的子类,先写父类,再写遵循的协议
class Man : Person, MarryProtocol, DivorceProtocol {
@objc func cook() {
print("还好去新东方学了几年的厨艺,终于可以大展身手")
}
@objc func wash() {
print("还好买了台洗衣机")
} func DivideMoney() {
print("分财产")
}
} // 创建一个男人
var man = Man(name: "韦小宝", age: )
man.cook()
man.wash()
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 引入。 该关键字表示闭包的参数和返回值类型定义已经完成,闭包函数体即将开始。

 // MARK: - 闭包
// 求两个数的最大值
/*
在OC中使用Block实现
int (^block)(int a, int, b) = ^int (int a, int b) {
return a > b ? a : b;
}
*/ // 使用闭包
var myBlock : ((a : Int, b : Int) -> Int) // 第一种方式
myBlock = {
(a : Int, b : Int) -> Int in
return a > b ? a : b
} // 第二种方式
myBlock = {
(a, b) -> Int in
return a > b ? a : b
} // 第三种方式
myBlock = {
a, b in
return a > b ? a : b
} // 第四种方式
myBlock = {
a, b in
// 不用return关键字
a > b ? a : b
} // 第五种方式
myBlock = {
a, b in
return a > b ? a : b
} let max = myBlock(a: , b: )
print(max)