SwiftUI 学习笔记 10:类
这是一个强大的功能,这是毫无疑问的,并且在开始构建真正的iOS应用程序时也没有避免使用类的方法。但是请记住要使代码简单:仅仅因为功能存在,并不意味着你需要使用它。正如马丁·福勒(Martin Fowler)所说,“任何傻瓜都可以编写计算机可以理解的代码,但是优秀的程序员可以编写人类可以理解的代码。”
创建类
类与结构相似,但是不自带初始化器,所以必须添加初始化相关的代码。
1 | class Dog { |
创建该类的实例看起来就像是一个结构一样:
1 | let poppy = Dog(name: "Poppy", breed: "Poodle") |
其他例子:
1 | class Empty { } |
类的继承
第二个与结构不同的是类具有继承能力。继承的类为子类,被继承为父类。例如我们有一个类:
1 | class Dog { |
这个类我们可以用一个子类来继承它,通过class <子类名称>: <父类名称>
的形式继承。这个子类拥有父类所有的属性和初始化方法:
1 | class Poodle: Dog { |
有的时候我们还需要自定义子类的初始化参数,例如Poodle
的类我们知道它的breed
将始终为Poodle
,所以我们给子类的初始化器传递数值:
1 | class Poodle: Dog { |
出于安全原因,Swift总是让你super.init()
从子类进行调用-以防万一父类在创建时会做一些重要的工作。
其他例子:
1 | class Handbag { |
覆盖方法
子类可以替换父类的方法(覆盖不会改变父类的方法,只是在子类中不使用父类方法并替换一个新的方法)例如:
1 | class Dog { |
这是一个普通类,我们创建一个子类来继承它:
1 | class Poodle: Dog { |
我们可以将父类Dog
的makeNoise
方法覆盖重写,我们可以将第二段的代码修改为:
1 | class Poodle: Dog { |
Swift要求我们在重载方法时使用override func
而不是仅仅使用func
。它阻止你无意中重载方法,并且如果你尝试重载父类中不存在的内容,则会收到错误消息:
进行此更改后,poppy.makeNoise()将打印“ Yip!”而不是“ Woof!”。
为了证明这个操作不会更改父类的方法,我对代码进行微小的调整:
1 | class Dog { |
禁止继承(最终类)
有的时候我们不想让其他开发人员来继承你的类,你可以使用final class
来表达该类不可以被继承,例如:
1 | final class Zhhoo { |
复制对象
和结构不同,类的直接复制(a = b,c = a
这种形式)会让所有类都指向同一件事,他们之间互相干扰。而结构不会:
例如我们创建一个简单的类:
1 | class Singer { |
如果创建该类的实例并打印其名称,则将得到“ Taylor Swift”:
1 | var singer = Singer() |
现在让我们创建一个新的变量,并且重新定义这个类中变量的名称:
1 | var singerCopy = singer |
由于该方法的类的工作,既singer
和singerCopy
指向内存中的同一个对象,所以当我们打印歌手的名字,我们再次看到“贾斯汀比伯”:
1 | print(singer.name) |
另一方面,如果Singer是一个结构,那么我们将第二次打印“ Taylor Swift”:
1 | struct Singer { |
例子:
在类中
a=b c=b print(a) != print(c)
a=b c=a d=a print(c) = print(d)
a=b c=a print(a) = print(c)
反初始化器
类与结构的不同,还有一点就是类支持反初始化器deinit
。反初始化器可以在实例被销毁的时候执行。例如:
这是一个Person
带有name
属性,简单的初始化程序和printGreeting()
打印消息的方法的类:
1 | class Person { |
我们将Person
在循环中创建该类的一些实例,因为每次循环进行时,都会创建一个新人员,然后将其销毁:
1 | for _ in 1...3 { |
现在用于反初始化程序。Person实例销毁时将调用此方法:
1 | class Person { |
其他例子:
1 | class IceCream { |
可变性
类和结构之间的最终区别是它们处理常量的方式。如果你具有带有可变属性的常量结构,则该属性不能更改,因为结构本身是常量。
但是,如果你的常量类具有可变属性,则可以更改该属性。因此,类不需要mutating
带有更改属性的方法的关键字。只有结构才需要。
这种差异意味着即使将类创建为常量,也可以更改类的任何变量属性–这是完全有效的代码:
1 | class Singer { |
如果要阻止这种情况发生,则需要使该属性不变:
1 | class Singer { |
其他例子:
1 | class Pizza { |
在结构struct
中的例子:
1 | struct Barbecue { |
总结
- 类和结构相似,它们都可以让你使用属性和方法创建自己的类型。
- 一个类可以从另一个类继承,并获得父类的所有属性和方法。谈论类层次结构是很常见的–一个类基于另一个类,而另一个类本身又基于另一个类。
- 你可以使用final关键字标记一个类,这将阻止其他类从该类继承。
- 通过方法覆盖,子类可以使用新的实现替换其父类中的方法。
- 当两个变量指向同一类实例时,它们都指向同一块内存–改变一个会改变另一个。
- 类可以具有一个反初始化器,该反初始化器是在销毁该类的实例时运行的代码。
- 类并不像构造结构那样强烈地强制执行常量–如果将属性声明为变量,则无论如何创建类实例,都可以对其进行更改。
参考资料
- 感谢你赐予我前进的力量