required
用
required
修饰指定初始化器
,表明其所有子类
都必须实现该初始化器
(通过继承或重写实现)
如果子类重写了required初始化器,也必须加上required,不用加上override
class Person {
required init() {
}
init(age:Int) {
print(age)
}
}
class Student : Person {
init(score:Int) {
super.init(age: 0)
}
required init() {
super.init()
}
}
属性观察器
父类的属性在它自己的初始化器中赋值不会触发属性观察器,但是在子类的初始化器中赋值会触发属性观察器
class Person {
var age: Int {
willSet {
print("willSet",newValue)
}
didSet {
print("didSet",oldValue,age)
}
}
init() {
self.age = 0
}
}
class Student: Person {
override init() {
super.init()
self.age = 1
}
}
/// wllSet 1
/// willSet 0 1
var stu = Student()
可失败初始化器
类、结构体、枚举都可以使用
init?
定义可失败初始化器
class Person {
var name: String
init?(name:String) {
if name.isEmpty {
return nil
}
self.name = name
}
}
之前接触过的可失败初始化器
var num = Int("123")
enum Answer : Int {
case wrong,right
}
var an = Answer(rawValue:1)
(1)不允许同时定义参数标签、参数个数、参数类型相同的可失败初始化器和非可失败初始化器
(2)可以用init!
定义隐式解包的可失败初始化器
(3)可失败初始化器可以调用非可失败初始化器
,非可失败初始化器调用可失败初始化器需要进行解包
(4)如果初始化器调用一个可失败初始化器导致初始化失败,那么整个过程都失败,并且之后的代码都停止执行
(5)可以用一个非可失败初始化器重写一个可失败初始化器
,但反过来不可以
反初始化器deinit
deinit
叫做反初始化器,类似于C++的析构函数
、OC的dealloc方法
当类的实例对象被释放内存时,就会调用实例对象的deinit方法
deinit不接受任何参数,不能写小括号,不能自行调用
父类的deinit
能被子类继承
子类的deinit实现执行完毕后会调用父类的deinit
class Person {
deinit {
print("person对象被释放了")
}
}
可选链(Optional Chainning)
(1)
如果可选项为nil,调用方法、下标、属性失败,结果为nil
(2)如果可选项不为nil,调用方法、下标、属性成功,结果会被包装成可选项
(3)如果结果本来就是可选项
,不会进行再次包装
(4)多个?
可以链接在一起(如果链接中任何一个节点为nil
,那么整个链就会调用失败
)
class Car {
var price = 0
}
class Dog {
var weight = 0
}
class Person {
var name: String = ""
var dog: Dog = Dog()
var car: Car? = Car()
func age() -> Int { 18 }
func eat() -> () { print("Person eat") }
subscript(index:Int) -> Int{index}
}
func getName() -> String {
"Jack"
}
var person: Person? = Person()
var age1 = person!.age() /// Int
var age2 = person?.age() /// Int?
var name = person?.name /// String?
var index = person?[6] /// Int?
/// 如果person为nil,那么不会调用getName()
person?.name = getName()
if let _ = person?.eat() {
print("eat 调用成功")
}else{
print("eat 调用失败")
}
var dog = person?.dog /// Dog?
var weight = person?.dog.weight /// Int?
var price = person?.car?.price /// Int?
var scores = [
"Jack":[86,82,84],
"Rose":[79,94,81]
]
var num1: Int? = 5
/// 表示num1不为nil的时候,才会个num1赋值10
num1? = 10
var num2: Int? = nil
num2? = 10
协议(Protocol)
(1)协议可以用来
定义方法、属性、下标
的声明
,协议可以被枚举、结构体、类遵守
(多个协议之间用逗号隔开)
(2)协议中定义方法
时不能有默认参数值
(3)默认
情况下,协议中定义的内容必须全部实现
protocol Drawable {
/// 只做声明
/// get set 表示可读可写
/// get 表示只读
/// 不限制属性是计算属性还是存储属性
var x: Int {get set}
var y: Int {get}
func draw()
subscript(index:Int) -> Int {get set}
}
protocol Test1 {}
protocol Test2 {}
protocol Test3 {}
class TestClass: Test1,Test2,Test3 { }
协议中的属性
(1)协议中定义的属性
时必须用var
关键字
(2)实现协议时
的属性权限要不小于
协议中定义 的属性权限
协议定义get、set,用var存储属性或get、set计算属性去是实现
协议定义get,用任何属性都可以是实现
/// 方式一:存储属性
class Person: Drawable {
var x: Int = 0
let y: Int = 0
func draw() {
print("Person")
}
subscript(index: Int) -> Int {
get { index }
set {}
}
}
/// 方式二: 计算属性
class Person : Drawable {
var x: Int {
set{ }
get{ 0 }
}
var y: Int { 0 }
func draw() {
print("Person draw")
}
subscript(index: Int) -> Int {
set{}
get{index}
}
}
协议中的static、class
为了保证通用,协议中必须用static定义类型方法、类型属性
、类型下标
(因为结构体和枚举也可以遵守协议,而clas只能是定义类的类型方法)
protocol Drawable {
static func draw()
}
class Person1: Drawable {
class func draw() {
print("Person1 draw")
}
}
class Person2: Drawable {
static func draw() {
print("Person2 draw")
}
}
协议中的mutating
只有将协议中的实例方法标记为mutating
才允许结构体、枚举
的具体实现修改自身的内存(属性)
类在实现方法时不用加mutating,枚举、结构体才需要加mutating
protocol Drawable {
mutating func draw()
}
class Size: Drawable {
var width: Int = 0
func draw() {
width = 10
}
}
struct Point: Drawable {
var x: Int = 0
mutating func draw() {
x = 10
}
}
协议中的init
协议中还可以定义初始化器init
非final类实现时必须加上required
protocol Drawable {
init(x:Int,y:Int)
}
class Size: Drawable {
required init(x: Int, y: Int) {
}
}
final class Point: Drawable {
init(x: Int, y: Int) {
}
}
如果
从协议实现的初始化器,刚好是重写了父类的指定初始化器
那么这个初始化器必须同时加上required、override
protocol Livable {
init(age:Int)
}
class Person {
init(age:Int) {
}
}
class student: Person,Livable {
required override init(age: Int) {
super.init(age: age)
}
}
协议中init、init?、init!
协议中定义的init?、init!,可以用init、init?、init! 去实现
协议中定义的init,可以用init、init!去实现
protocol Livable {
init()
init?(age:Int)
init!(no:Int)
}
class Person: Livable {
required init() {}
// required init!() {}
required init?(age: Int) {}
// required init!(age: Int) {}
// required init(age: Int) {}
required init!(no: Int) {}
// required init?(no: Int) {}
// required init(no: Int) {}
}
协议的继承
一个协议可以继承其他协议
protocol Runnable {
func run()
}
protocol Livable : Runnable {
func breath()
}
class Person: Livable {
func run() {
}
func breath() {
}
}
协议的组合
协议组合,可以包含1个类类型(最多1个)
protocol Runnable {}
protocol Livable {}
class Person {}
/// 接收Person或者其子类的实例
func fn0(obj:Person) {}
/// 接收遵守Livable协议的实例
func fn1(obj:Livable) {}
/// 接收同时遵守Livable、runnable协议的实例
func fn2(obj:Livable & Runnable) {}
/// 接收同时遵守Livable、Runnable协议,并且是Person或其子类的实例
func fn3(obj:Person & Livable & Runnable) {}
/// 协议组合起别名
typealias RealPerson = Person & Livable & Runnable
func fn4(obj:RealPerson) {}
CaseInterable
协议
让枚举遵守CaseInterable协议,可以实现遍历枚举
enum Season : CaseIterable {
case spring,summer,autumn,winter
}
let seasons = Season.allCases
for season in seasons {
print(season)
}
CustomStringConvertible
遵守CustomStringConverible协议,可以自定义实例的打印字符串
class Person: CustomStringConvertible {
var age: Int
var name: String
init(age:Int ,name: String) {
self.age = age
self.name = name
}
var description: String {
"age=\(age), name=\(name)"
}
}
var p = Person(age: 18, name: "lili")
/// age=18,name=lili
print(p)
Any、AnyObject
Swift提供了2种特殊类型: Any、AnyObject
Any
: 可以代表任意类型(枚举
、结构体
、类
,也包括函数类型
)
AnyObject
: 可以代表任意类
类型(在协议后面写上:AnyObject表示只有类能遵守这个协议
)
class Student {
}
var stu: Any = 10
stu = "jack"
stu = Student()
var data = Array()
data.append(1)
data.append(3.14)
data.append("jack")
is 、as、as?、as!
is
用来判断是否为某种类型
as
用来做强制类型转换
protocol Runnable {
func run()
}
class Person { }
class Student: Person,Runnable {
func run() {
print("Student run")
}
func study() {
print("Student study")
}
}
var stu: Any = 10
print(stu is Int) /// ture
stu = "Jack"
print(stu is String) /// true
stu = Student()
print(stu is Person) /// true
print(stu is Student) /// true
print(stu is Runnable) /// true
var stu: Any = 10
(stu as? Student)?.study() /// 没有调用study(因为强制转换失败)
stu = Student()
(stu as? Student)?.study() /// student study
(stu as! Student).study() /// student study
(stu as? Runnable)?.run() /// student run
X.self 、 X.Type、AnyClass
X.self
是一个元类型(metadata)的指针
,metadata存放着类型相关的信息
X.self属于X.Type类型
class Person {}
class Student : Person {}
var perType: Person.Type = Person.self
var stuType: Student.Type = Student.self
perType = Student.self
var anyType: AnyObject.Type = Person.self
anyType = Student.self
public typealias AnyClass = AnyObject.Type
var anyType2: AnyClass = Person.self
anyType2 = Student.self
var per = Person()
var perType = type(of: per) /// Person.self
print(Person.self == type(of: per)) /// true
元类型的应用
class Animal {
required init(){
}
}
class Cat : Animal {}
class Dog : Animal {}
class Pig : Animal {}
func create(_ clses:[Animal.Type]) -> [Animal] {
var arr = [Animal]()
for cls in clses {
/// 前提条件是: cls都有init初始化器,所有其父类中使用required修饰init
arr.append(cls.init())
}
return arr
}
print(create([Cat.self,Dog.self,Pig.self]))
Self
Self 一般作返回值类型,
限定返回值跟方法调用者必须是同一个类型
(也可以作为参数类型)
protocol Runnable {
func test() -> Self
}
class Person: Runnable {
required init() {}
func test() -> Self {
/// 返回的必须是调用者的类型
/// 这里不能直接返回Person.init()
/// 这是因为如果其子类调用这个方法那么返回的类型会对不上
type(of: self).init()
}
}
class Student : Person {}
var p = Person()
/// Person
print(p.test())
var stu = Student()
/// Student
print(stu.test())