好吧,让我们从头来过。什么是对象编程编程呢?
先让我们从上往下理解:人是一个喜欢归类的动物,所以有生物学上的纲目。纲,即是我们编程里的基类(也叫父类);目,即是我们编程里的派生类(也叫子类)。基类与派生类是相对而言的,但跟纲目一样,都是以相同特征、行为来划分的集合,同时派生类是基类特征、行为的延伸与拓展。特征在这里叫属性,行为在这里叫方法,这也是类的基本。另外,同生物学上的趋同进化一样,不同的类需要共同的方法时,我们使用了协议。所以协议是一种夸类别的同一行为。
再让我们从下往上理解:当多行语句需要重复使用,我们把它们归集在一起,称为 函数。当多个函数需要联合使用时,我们又把它们归集在一起,有的称为 库,有的称为 类。单说类这边,为了有所区别,只好称类里面的函数为 方法,共用的变量为 属性。到了这一步,我们只能基于集合(类)调用方法与属性了,称为 封装;而有些方法、属性只是用于内部流程,所以有多事的分了 私有与 公有;用着用着,感觉以前的函数、变量能全局范围里直接使用也挺好,于是来一个 静态方法、静态变量;当类多了起来,又看到某些类有共同部分,于是又把它归集出来,称为 基类;剩下各自不同的部分称为 派生类;派生类不想把相同的部分都写上,于是用 继承;即然它们有共同的部分,派生类一定范围上可作基类用,称为 多态;基类的部分方法只做约定,于是有了 抽象方法;有抽象方法的类叫 抽象类;忽然发现某派生类继承的方法不适当怎么办?那重写呗,所以有 重写;一个类不仅与甲有相同部分还与乙也有相同部分,怎么办?那就来个 多继承;哎呀呀,多继承又出错了,怎么办?精简,跟乙的相同部分不能太具体,好,就这样定了,再改过名字称为 协议。同样的事情要针对不同的数据类型写好几个方法称为 重载;这样太麻烦了,搞出个 泛型……。
之如此类,所以我一直认为类是过度集合的产物。
新的编程语言,有一些不再拘泥面向对象编程,它们同时支持函数式编程与面向对象编程。Swift是其中之一,所以我们是幸福的。
到这里,我们将开始军团化作战训练。你没看错,面向对象编程,就是程序开发中的军团化作战。所以你就是那未来的海陆空三军(Enumeration 枚举、Structure 结构体、 Class 类)总司令。矮油,统一全宇宙的任务就交给你了。
所以,这一章我们将学习Enumeration 枚举、Structure 结构体、 Class 类。让我们一起加油吧!
慢着,如果你有面向对象编程的开发经验,你可能只需要了解下面12点。其中Enumeration 枚举有4点,Structure 结构与Class 类有6点,其余的有2点。
Enumeration 枚举、Structure 结构体,是值类型,Class是引用类型。值类型定义为常量后不能修改其元素值,引用类型则可以。
Structure 结构体、Class 类,最大的不同之处在于前者不能继承,其余的在应用上基本相同。
泛型、协议上与其它语言没什么区别。
- Enumeration 枚举可定义为不同类型。
enum
2. Enumeration 枚举可以嵌套。
enum
3. Enumeration 枚举可使用参数,这一点极大丰富了枚举的应用。
enum
4. Enumeration 枚举可使用递归 ,方法是:枚举使用的参数,设置其类型为当前枚举类型。
enum
5. Structure 结构体 、Class 类,使用init作构造函数,使用self指实例自身。
struct
6. Structure 结构体 、Class 类, init方法可重载,只需要参数名不同即可。init方法中重载的需要调用Designated的,其中Class 类中需要使用关键词convenience.
struct
7. Structure 结构体 、Class 类,不初始化的变量需添可选值符号“?”。未标记的则需在初始化时赋值。
struct
8. Structure 结构体 、Class 类,支持subscript 下标语法。使用字典或数组的方式赋值与取值。
class
9. Structure 结构体 、Class 类, 支持Extension 拓展。使用关键词extension对已有结构体与类实现新的功能。
extension
10. Structure 结构体 、Class 类,支持Delegate 委托 、 Protocol 协议。Delegate 委托在实际开发中需要使用,这里介绍一下。
/** 1. 定义一下协议 **/
11. Optional Chaining 可选链,使用“?”、“!”。这个非常强大。“?”表示:没有返回nil,有返回值。“!”表示:确定有,没有返回系统错误。
let
12. as,is 。as的作用:从子类对象转换为父类对象,向上转型使用;消除二义性,数值类型转换。is的作用:判断某个对象是否是某个特定类的对象。
let
好,我们还是假装以前没学过编程,较细致的来一遍。主要涉及Enumeration 枚举、Structure 结构体、Class 类型。在Swift中Enumeration 枚举、Structure 结构体经过了强化,能承担更多的工作。
一、Enumeration 枚举,枚举是有并列特性的数据的集合。
Enumeration 枚举最原始的作用是:让数据具有可读性。通过下面示例可以看出枚举在这方面的优势。
/** 定义方向枚举 **/
Enumeration 枚举在Swift支持不同的数据类型。这个可能是为支持参数化与嵌套的产物,否则我没看出其有积极意义。
/** 定义Int值的枚举 **/
Enumeration 枚举嵌套,嵌套让枚举有了多重归集的功能。
/** 枚举嵌套 **/
Enumeration 枚举支持元素带参数,我把它近似的理解成函数类型。
/** 枚举支持元素带参数 **/
Enumeration 枚举支持元素带参数,并形成递归应用。这一个要仔细看,有点绕。
/** 递归枚举 **/
二、Structure 结构体 、 Class 类、Protocol协议。
- Structure 结构体定义与调用。
/** Structure 结构体 **/
- Class 类定义与调用。
/** Class 类 **/
- Protocol 协议定义。协议等待着被实现。
/** Protocol 协议 **/
- Structure 结构体、Class 类,结构体与类的共同点:
Properties 属性。可以有属性,等同于变量与常量。
Methods 方法。可以有方法,等同于函数。
Subscripts 下标语法。支持下标语法,类似于数组、字典的元素赋值与取值。
Initialization 构造 。可以有构造函数,如果未定义,则系统分配init()作构造函数。
Extensions 拓展。支持拓展,可向一个已有的类、结构体添加新功能。
Protocols 协议。支持实现协议。
下示例中用来说明Structure 结构体与Class 类相同部分。可将尝试运行后,再将关键字struct换为class运行。
/** 协议 **/
- Class 类,特有的特征:
Inheritance 继承,类有可继承性。
Deinitialization 析构,通过析构函数来实现,类实例消毁时调用。
Type Casting 类型转换,判断实例的类型,通过is, as将其看做是父类或者子类的实例。
Automatic Reference Counting 自动引用计,所以纳入了自动内存管理机制。
// 示例为读取配置文件的类。将文件数据转为配置字典未实现。
当你不需要继承,Swift建议你使用Structure替代Class,这样性能更高。
- 除了上面大方向的相同与不同,其实在编写时还存在下面一些相同与不同点:
当Structure 结构体、Class 类,没有实现构造函数时,系统隐式的提供一个无参数的构造函数。
在Structure 结构体、Class 类中,以let定义的属性,可以在构造函数里再赋值。我喜欢这个。
在Structure 结构体、Class 类中,不想被初始化的属性,需要使用var定义,并在最后加上"?"。
在Structure 结构体、Class 类中,系统为subscript赋值,提供关键词“newValue“,表示set(key, value)中发value。
结构体实例赋予常量时,实例的属性值不能改变,而类则可以。
结构体在没有构造函数时也能使用参数进行实例,而类不可以。
结构体内部方法给其或其属性赋值时,该方法需要添加”mutating“限定词, Enum枚举也一样
Structure 结构体的应用实例:
struct
class 类的应用实例。
class
- class 类的继承,Designated、Convenience、Required。
Designated:是Swift走向有序化的最重要的一步。保证初始化时非选值属性被赋值。
Convenience:一种便捷方式。原则,是需要调用本类的Designated的初始化方法。
Required:确定该初始方法一定要在派生类中重写。
/** 基类 **/
- 协议与委托。
我们定义了一个聊天的组件,它将应用于聊天室的页面上。
我们需要像下面这样定义委托,才能使用组件上输入的信息显示在页面上。
/** 1. 定义一下协议 **/
- init?、init! 可能失败的初始化。
init? 表示可失败初始化器,失败的时候,return nil。
init! 表示可失败初始化器,只不过这个失败要求触发断言。
import
- Property Observer 属性观察员,提代两个方法willSet、didSet来监听属性值的变化。
class
- static 静态属性,理论是一种全局数据,通过定义的名称来调用。
struct
- private 、public、open,修饰类的属性与方法。
private 当前类内使用
public 可以在其他作用域被访问,但是不能在override、extension中被访问
open 可以在其他作用域被访问
三、一些语法糖特征:
- lazy 延迟加载,用的时候才赋值(分配内存),相当于这个事就这么定了,到用的时间再处里。
let
- 可选型链。
使用“?”,这是我最喜欢的语法糖。特别是从Go的JSON解析中走出来的人,在这里再也不用一层层去判断了。
“?”是判断行不行,不行就返nil,行就继续。“!”是一定可以的,不行则返回系统错误。
/** 多层的Dictionary, 用Go里想死的心都有,在这里就简单多了,那一层没有,就直接回空。 **/
- Error Handling 错误处理。错误处理有四种处理方式:
向调用者执出错误。使用调用者时,仍需要处理错误。
使用do-catch语句处理。完全处理错误。
将错误作为可选值处理。使用try?,有错误,返回nil。无错误,返回值。
断言错误不会发生。使用try!,有错误,抛出系统错误,无错误,返回值。
下面是一个用户在商店用积分购买商品提交订单的示例。用户购物时有四种状态,未登录、登录但不是会员、会员购买的商品不需要积分,会员的积分不够购买商品。本例用Error Handling来的四种方式来处理,当然你也可以用其它方式来处理。
import
- 泛型,是为了解决类似于方法重载的问题。
/** 定义一个交换值的方法, 需要为Int,Double之类各写一个, 共计n个 **/
泛型约束。类型约束指定了一个必须继承自指定类的类型参数,或者遵循一个特定的协议或协议构成。
func
下一篇,MacOS界面设计。
让我们在这里,遇见明天的自己!姜友华