Swift中类(Class)和 结构体(Struct)
分析
共同点:
- 定义属性用于存储值
- 定义方法用于提供功能
- 定义下标操作使得可以通过下标语法来访问实例所包含的值
- 定义构造器用于生成初始化值
- 通过扩展以增加默认实现的功能
- 实现协议以提供某种标准功能
与结构体相比,类还有如下的附加功能:
- 继承允许一个类继承另一个类的特征
- 类型转换允许在运行时检查和解释一个类实例的类型
- 析构器允许一个类实例释放任何其所被分配的资源
- 引用计数允许对一个类的多次引用(对象引用)结构体总是通过被复制的方式在代码中传递,不使用引用计数。
逐一对比
定义
//: ### 定义
class StudentClass{ }
struct StudebtStruct{ }
定义存储属性
//: > 类中定义的存储属性,如果不是可选类型,需要进行初始化;结构体则默认带有初始化方法
class StudentC01{
var name: String!
}
struct StudebtS01{
var name: String!
}
定义属性函数function
//: ### 定义属性函数function
//: > 类中可以使用 static 和 class两种修饰符;但是结构体中只能使用static修饰
class StudentC02{
static var des:String = "学生的类"
var name:String!
@objc class func objc_describe()->String{
return des
}
class func class_describe()->String{
return des
}
static func static_describe()->String{
return des
}
}
struct StudentS02{
static var des:String = "学生的结构体"
var name:String!
static func describe()->String{
return "这是一个定义学生的类"
}
}
扩展下标
//: ### 扩展下标
//: > *subscript*
class StudentC003{
var names:[String] = ["1","2","3","4","5"]
subscript (index:Int)->String?{
get{
if names.count <= index{
return nil
}
return names[index]
}
}
}
struct StudentS003{
var names:[String] = ["1","2","3","4","5"]
subscript (index:Int)->String?{
get{
if names.count <= index{
return nil
}
return names[index]
}
}
}
let sc003 = StudentC003()
sc003[1]// 2
let ss003 = StudentS003()
ss003[1]// 2
初始化
//: ### 初始化
//: > 结构体自带初始化方法(可以不写初始化方法);
//: > 类必须手写init方法,否则报错;
class StudentC004{
var name:String
init(name:String) {
self.name = name
}
}
struct StudentS004 {
var name:String
}
let studentc004 = StudentC004(name: "行走在北方")
let students004 = StudentS004(name: "行走在北方")
扩展功能 Extention
//: ### 扩展功能 Extention
extension StudentC004{
func discribe() -> String {
return "student class:"+self.name
}
}
extension StudentS004{
func discribe() -> String {
return "student struct:" + self.name
}
}
实现协议 protocol
//: ### 实现协议 protocol
//: * 定义协议
protocol Capacity {
func draw()//协议方法
}
//: * 实现协议方法
class StudentC05:Capacity{
internal func draw() {
}
var name:String
init(name:String) {
self.name = name
}
}
struct StudentS05:Capacity{
internal func draw() {
}
var name:String
}
mutating 关键字的使用
科普下:
-
枚举和结构体都是值类型,Swift默认值类型的对象方法不能修改属性值,但是如果一定要修改 那就在函数前面添加mutating关键字
-
计算属性setter方法中不需要更改属性值的时候,不需要添加mutating关键字;
-
计算属性setter方法中更改属性值的时候,必须要添加mutating关键字
protocol Action{
var myY:Int{
mutating get
}
}
struct Point {
var x:Int
var y:Int
mutating func modifyX(x: Int){
self.x = x
}
var myY:Int{
mutating get {//getter方法前面添加mutating关键字
self.y = self.y*2
return y
}
}
}
class ActionClass {
var name:String?
init(name:String) {
self.name = name
}
var myName:String? {
get {// class 是对象类型 可以直接修改
self.name = "666 -> :" + self.name!
return self.name
}
}
}
let actionclass = ActionClass(name: "NB")
判断两个对象地址是否相同(验证 引用类型 和 值类型)
//: ### 判断两个对象地址是否相同
//: > 类是引用类型;结构体是值类型;结构体不能通过=== 、!==类判断比较
//: >
class StudentC07{
var name: String
init(name:String) {
self.name = name
}
}
let studentc071 = StudentC07(name: "原始名字")
var studentc072 = studentc071
studentc071.name = "新名字"
print("student071:\(studentc071.name)\nstudent072:\(studentc072.name)")
if studentc071 === studentc072 {
print("类是引用类型,最终指向同一块内存")
}
struct StudentS07{
var name: String
init(name:String) {
self.name = name
}
}
let students071 = StudentS07(name: "结构体:原始名字")
var students072 = students071
students072.name = "结构体:新名字"
print("students071:\(students071.name)\nstudents072\(students072.name)")
deinit 释放资源
//: ### deinit 释放资源
//: > 类有deinit方法;结构体中没有deinit方法。
class StudentC08{
var name: String
init(name:String) {
self.name = name
}
deinit {
//这里释放资源
}
}
lazy:延迟属性(懒加载)
class 有延迟属性;struct没有延迟属性
//: > 延迟存储属性是指当第一次被调用的时候才会计算其初始值的属性。在属性声明前使用 lazy 来标示一个延迟存储属性
class Importor{
var fileName = "data.txt"
}
class DataManager{
lazy var importor = Importor()
var Data = [String]()
}
继承
//: ### 继承
//: > 类能继承;结构体不能继承。
class Person{
var name:String
init(name:String) {
self.name = name
}
}
class Student06: Person {
var score : Float
init(name: String, score: Float){
self.score = score//先给父类中没有的属性赋值,再调用父类init方法
super.init(name: name)
}
}
-
继承之后 可重写父类方法/属性
-
重写计算属性:只能增加功能不能减少功能——>父类中有setter getter,那么子类重写计算属性 setter getter都必须要有。父类中只有setter 子类中可以在重写setter的同时增加getter
-
final 关键字可以让属性不被重写 或者 继承
-
//: * 重写计算属性
//: * 重写对象方法
//: * 重写类方法
//: * 重写初始化方法
//: * 重写存储属性
//: _父类_
class Person{
//存储属性
var name:String = "person"
//计算属性
var rename:String{
return self.name
}
//初始化方法
init(_ name:String) {
self.name = name
}
//对象方法
func describe() -> String {
return self.name
}
//类方法
class func describeClass()->String{
return "这是一个描述人的类"
}
}
//: _子类_
class Man: Person {
//重写存储属性
override var name: String{
didSet{
print("man 对象中 name 的原始值:\(self.name)")
self.name = "man:"+self.name
}
}
var score : Double
//重写setter getter
override var rename: String{
set{
self.name = "man:"+newValue
}
get{
return "_"+self.name
}
}
//重写初始化方法
override init(_ name: String) {
self.score = 0.0
super.init(name)
}
//重写对象方法
override func describe() -> String {
return self.name + "_score:\(self.score)"
}
// 重写类方法
override class func describeClass() -> String {
return "我是描述男人的类"
}
}
var man00 = Man("kael")
print(man00.name)
class 的类型检测
- 首先在自己的初始化方法中先给自己的属性初始化
- 然后调用父类的初始化
- 最后修改父类的属性
//: ### 类型检测 is as?
var person01 = Person("person01")
var man01 = Man("man01")
if person01 is Person {
print("person01:我是Person")
}else{
print("person01:我不是Person")
}
if person01 is Man {
print("person01:我是Man")
}else{
print("person01:我不是Man")
}
if man01 is Person {
print("man01:我是Person")
}else{
print("man01:我不是Person")
}
if man01 is Man {
print("man01:我是Man")
}else{
print("man01:我不是Man")
}
if let p = person01 as? Person {
print("person01 是 Person")
}
if let p = person01 as? Man{
print("person01 是Man")
}else{
print("person01 不是Man")
}
if let p = man01 as? Person {
print("man01 是 Person")
}
if let p = man01 as? Man{
print("man01 是Man")
}else{
print("man01 不是Man")
}