更多内容,欢迎关注公众号:Swift花园
喜欢文章?不如来点赞关注吧?
Swift的类也能让你建立带有属性和方法的新类型,这一点和结构体很类似,可是它们之间有五个显著的区别。下面让我一一为你说明。编程
类和结构体的第一个区别是类没有逐一成员构造器。这意味着只要你的类里有属性,你就必须自行建立构造器。swift
举个例子:安全
class Dog { var name: String var breed: String init(name: String, breed: String) { self.name = name self.breed = breed } }复制代码
建立类的实例跟建立结构体的实例方式同样:markdown
let poppy = Dog(name: "Poppy", breed: "Poodle")复制代码
类和结构体的第二个区别是类能够继承已经存在的类。新的类继承了原始类全部的属性和方法。ide
这个过程被称为 类继承 或者 子类化, 被继承的类称为 “父类” 或者 “超类”, 而新的类称为 “子类” 。spa
下面是一个 Dog
类:翻译
class Dog { var name: String var breed: String init(name: String, breed: String) { self.name = name self.breed = breed } }复制代码
如今让咱们基于 Dog
来建立一个新的类 Poodle
。默认状况下,它会继承 Dog
的全部属性以及构造器。code
class Poodle: Dog { }复制代码
不过,咱们也能够为 Poodle
建立本身的构造器。咱们知道这个类的 breed
属性老是 “Poodle”,所以咱们能够建立一个只有 name
属性的构造器。而且,咱们能够在 Poodle
的构造器里直接调用 Dog
的构造器,以便发生和 Dog
相同的构造过程。orm
class Poodle: Dog { init(name: String) { super.init(name: name, breed: "Poodle") } }复制代码
出于安全性考虑,Swift会要求你老是在子类里调用 super.init()
,以防止类在构造时来自父类的一些重要工做被遗漏。对象
子类能够将父类的方法替换为本身的实现,这个过程被称为 重写。 让咱们给 Dog
类添加一个 makeNoise()
方法:
class Dog { func makeNoise() { print("Woof!") } }复制代码
若是你建立一个 Poodle
类继承自 Dog
,它会继承 makeNoise()
方法。 “Woof!”:
class Poodle: Dog { } let poppy = Poodle() poppy.makeNoise()复制代码
方法重写使得咱们能够为 Poodle
类从新实现 makeNoise()
。
Swift要求咱们在重写方法时用 override func
而不是 func
,这个限定防止你在本身不知情的状况下偶然重写方法。另外,试图重写一个父类中并不存在的方法,你会遭遇错误。
class Poodle: Dog { override func makeNoise() { print("Yip!") } }复制代码
经过这个修改,poppy.makeNoise()
将打印出 “Yip!”,而不是 “Woof!”。
尽管类继承十分有用,而且苹果的平台在许多地方要求你大量使用它,有的时候你会但愿阻止其余开发者基于你的类构建新的类。
Swift给了咱们 final
关键字用于实现这种意图:当你把一个类声明为final时,将没有类可以继承它。这意味着没有人能经过重写方法来改变这个类的行为。
只须要把 final
关键字放在类前面,就像这样:
final class Dog { var name: String var breed: String init(name: String, breed: String) { self.name = name self.breed = breed } }复制代码
类和结构体的第三个区别是它们被复制的方式。当你复制一个结构体时,原始对象和复制体是不同的两个东西,改变其中一个并不会改变另一个。当你复制一个 类 时,原始对象和复制体都指向相同的东西,因此改变其中一个也会改变另外一个。
举个例子,有一个简单的 Singer
类,它有一个带有默认值的 name
属性:
class Singer { var name = "Taylor Swift" }复制代码
当咱们建立一个这个类的实例而且打印它的name时,咱们会获得“Taylor Swift”:
var singer = Singer() print(singer.name)复制代码
当咱们基于第一个实例建立第二实例而且改变第二个实例的name时:
var singerCopy = singer singerCopy.name = "Justin Bieber"复制代码
因为类的工做机制,singer
和 singerCopy
指向内存里的同一个对象。因此当咱们打印 singer的name时,咱们也会获得“Justin Bieber”:
print(singer.name)复制代码
另外一方面,假如 Singer
是一个结构体,那第二次咱们还将获得 “Taylor Swift”:
struct Singer { var name = "Taylor Swift" }复制代码
类和结构体的第四个区别是类有 析构器,它是一个类的实例被销毁时执行的代码。
这里有一个 Person
类,它有一个 name
属性,一个简单的构造器,以及一个打印信息的 printGreeting()
方法:
class Person { var name = "John Doe" init() { print("\(name) is alive!") } func printGreeting() { print("Hello, I'm \(name)") } }复制代码
咱们将利用循环建立几个 Person
类的实例,每次循环流转的时候,一个新的 Person
都会被建立,以后被销毁:
for _ in 1...3 { let person = Person() person.printGreeting() }复制代码
来到咱们的析构器。每当 Person
实例被销毁时,它的析构器都会被执行。
deinit { print("\(name) is no more!") }复制代码
类和结构体的最后一个区别是它们处理常量的方式。若是你有一个常量结构体,它有一个变量属性,那么这个变量属性是没法修改的。
可是,若是它是一个常量类,也有一个变量属性,那么这个变量属性是能够被修改的。基于这个区别,类的方法在改变属性时,并不须要 mutating
关键字,而结构体则须要。
这个区别意味着你能够修改类中的任何变量属性,即使类的实例自己被声明为常量。如下代码彻底合法:
class Singer { var name = "Taylor Swift" } let taylor = Singer() taylor.name = "Ed Sheeran" print(taylor.name)复制代码
若是你不想属性被修改,那么你必须直接将属性声明为常量。
class Singer { let name = "Taylor Swift" }复制代码
让咱们来总结一下。
final
关键字来标记一个类,这样能够阻止它被继承。
个人公众号
这里有Swift及计算机编程的相关文章,以及优秀国外文章翻译,欢迎关注~