面向对象总体概括:
Swift 不仅能够面向过程编程,也能够面向对象编程(OOP)。面向对象其实就是“以对象为核心”,把我们的客观世界想着是由一个个对象组成的,面向对象编程则为对象提供了属性和方法,属性就是为了描述对象的一些状态,方法则是告诉你对象该做什么。面向对象和核心就是“类”和“对象”!在我刚接触编程的时候,其实我也很容易把这东西混淆了,你要也是刚接触编程,能帮到你的,我觉得反而是时间。你要实在是有点难理解,就别去钻牛角尖,也许明天因为某个东西你就会恍然大悟。超喜欢那种感觉!
面向对象的三大特性: 继承 多态 封装 (封装和继承好理解,多态我在前面的博客中有提过,不理解可以往前面翻翻去看一下)。
Swift 面向对象编程的有五个单元: 枚举 结构体 类 扩展 协议
从整体的一个功能上看Swift的 枚举、结构体、类 三者具有完全平等的地位。(在后面我们会对这三者进行一个区分的)其他的面向对象编程的语言中都蛀牙提供了类一种单元,而Swift则有三种,大家想想,OC、Java等语言是面向对象编程的,Swift 是面向对象和过程都可以,Swift 是一门全新的语言,它才面世几年,而OC都快三十年了。所以Swift不简单,要是Swift刚出来那时候有人写出一个 println("Hello World")(2.0之前的写法) 就觉得它很简单,你真的就错了。Swift 不简单,你说简单估计是因为你也只研究到 print("Hello World"),哈哈......
在Swift中,枚举和结构体是值类型的,类是引用类型。值类型和引用类型的区别,我们后面说,先知道这一点。
在Swift的类、结构体、枚举中都可以定义(属性、方法、下标、构造体、嵌套类型),下面我们一个一个的用我小小的认识说一下它们,我也会给大家一些我看到的很不错的博客链接,方便大家更好的掌握,理解Swift。
一:枚举
Swift枚举是用来管理一组值的,当然也是有限的。比如一年四季你可以用枚举来管理,写个季节枚举,里面的值就是(春夏秋冬),还有性别(男女),再到我们的项目中比如经常看到的在即时通讯里面的消息类型(文字,图片,语音,系统消息)等等。比如下面的例子:
给大家看看我们在OC中是怎么定义枚举的,大家对比着理解:
/** 发送的消息类型 */ enum ZxMessageType: Int { case MessageTypeUnknown = 0 // 未知 case MessageTypeSystem // 系统 case MessageTypeText // 文字 case MessageTypeImage // 图片 case MessageTypeVoice // 语音 case MessageTypeVideo // 视频 case MessageTypeFile // 文件 case MessageTypeLocation // 位置 case MessageTypeShake // 抖动 }
// OC 枚举
/** * 消息类型 */ typedef NS_ENUM(NSInteger, TLMessageType){ MessageTypeUnknown, // 未知 MessageTypeSystem, // 系统 MessageTypeText, // 文字 MessageTypeImage, // 图片 MessageTypeVoice, // 语音 MessageTypeVideo, // 视频 MessageTypeFile, // 文件 MessageTypeLocation, // 位置 MessageTypeShake, // 抖动 };
顺便给大家提一下,上面这两种方式,是我自己的习惯,其实按照我们最开始学的时候的方式去定义没问题,只是在官方的定义中,OC和Swift都是上面例子的方式写枚举,这样写也有好处,有同行分析过了,链接这里。
Swift枚举和 C,OC 枚举的区别: Swift的枚举成员不会被分配一个默认的整数值,它的枚举名本身就是一个枚举实例和整数值之间可没有任何的关系。
Swift的知识点还有:枚举值和Switch语句 原始值 关联值 等几个方面,但我就不说了,说了也不会有前辈们总结的详细,我把知识点链接给大家,里面的内容足够掌握 Swift的枚举了!
二:类和结构体
把这两个放在一起,纯粹是因为这两个太像了,我们先把区别罗列出来,剩下的两者都一样。
1: 结构体是值类型,类是引用类型。
2: 结构体不支持继承,不支持类型转换。(值类型原因)
3: 结构体不支持定义析构器。 (后面提析构器的时候说)
插入说个问题: 实例 和 对象 的问题,在以前的OC中,对象就是实例,实例就是对象。但在Swift 中,以前记得看书的时候说是有 类 的实例才能叫做 对象,而 结构体 和 枚举 的实例只能叫做实例,不能叫做对象。我觉得应该是和它们之间的类型有关系,他们之间最主要的区别其实也都是围绕着 值类型和引用类型展开的。
看看类的定义:
class name: super class { // code // 构造器 // 属性 // 方法 // 下标 }
注意点:
1: 当我们自己不为结构体/类 提供构造器时,系统为结构体生成两个构造器,一个是无参数的构造器,一个初始化所有存储属性的构造器。如果希望用户定义的构造器与系统提供的构造器同时存在,则不能直接在类中定义构造器,可用扩展来添加。
2: Swift 的属性分为两类,存储属性 和 计算属性 ,存储属性类似于OC中的实例变量,它用来保存类型本身或者实例变量的状态数据。计算属性相当于OC中用setter和getter合成的 property 属性,它并不一定保存数据。
三:存储和计算属性
(一) 存储属性
Swift 定义存储属性的方法和定义它变量常量的方法相同,我们就不累赘。
存储属性可以分为 实例存储属性 类型存储属性 两类。这个可以参考OC的实例方法和类型方法,实例变量和类型变量一样的道理去理解。
注意点:
1 : 枚举不能定义 实例存储属性, 类和结构体可以。
2 : Swift 要求所有的存储属性都必须显式的制定初始值,要么你在定义的时候指定初始值,要么你在构造器里面指定初始值。
3 : 如果将存储属性的类型申明为可选类型,系统就可以将这些属性的初始值设置为 nil (大家一定注意,Swift的nil和OC的nil完全不一样,Swift的nil是一个确定的值,叫缺失值,而OC的nil是一个不指向任何类型的指针)。
比如定义的一个 model;
class ZxUser: NSObject { var username:String = "" var userID:String = "" var nikename:String = "" var avatarURL:String = "" var motto:String = "" var phoneNumber:String = "" var pinyin:String = "" var initial:String = "" }
在存储属性里面,我们要注意的是这个,延迟存储属性,延迟存储属性是指在第一次调用时才会被计算初始值的属性,声明延迟存储属性需要使用 Lazy 修饰符。
我们OC里面常用到的懒加载就是延时存储属性,我们看一个具体的例子就明白了:比如我们懒加载这个 ZxMessageModel 类型的数组,写法如下:
lazy var dataArray: Array<ZxMessageModel> = { // 弱引用防止循环引用写法 // [weak self] in // [unowned self] in // __weak typeof (self) Wself = self let dataArray:Array = Array<ZxMessageModel>() return dataArray }()
至于懒加载为什么这样写,有什么好处,看下面的链接!
Swift 懒加载(lazy) 和 Objective-C 懒加载的区别
(二) 计算属性
计算属性只能定义成变量形式,也就只能用 var 修饰。
计算属性就是相当于我们 OC 和 JAVA中通过 setter 和 getter 合成的属性(property属性)是一样的。
我们在OC中经常会这样用一个 property 属性,在.h中声明了这个属性,在.m中我们写它的 set 或者 get 方法,然后在他们的 set 或者 get 方法里面做一些操作,看下面的这个例子:
// 依据不同的条件判断返回不同的值 var cellHeight:CGFloat{ get{ switch self.messageType! { case ZxMessageType(rawValue:2)!: return self.messageSize.height + 40 > 60 ? self.messageSize.height + 40 :60 case ZxMessageType(rawValue:3)!: return self.messageSize.height + 20; default: break } return 0 } }
// 依据不同的消息类型设置不同的 cellIndentify var messageType:ZxMessageType?{ get{ return self.messageType } set { switch messageType! { case ZxMessageType(rawValue:2)!: self.cellIndentify = "TextMessageCell"; case ZxMessageType(rawValue:3)!: self.cellIndentify = "ImageMessageCell"; case ZxMessageType(rawValue:4)!: self.cellIndentify = "VoiceMessageCell"; case ZxMessageType(rawValue:5)!: self.cellIndentify = "SystemMessageCell"; default: break } } }
学习链接:
四:属性观察者
willSet(newValue): 被观察的属性即将被赋值之前自动调用该方法。
didSet(oldValue): 被观察的属性被赋值完成之后自动调用该方法。
上面的形参名是Swift隐式为它们提供的,你可以在方法中直接调用,扣上面字眼去理解它们的定义和使用;
var nameString = ""{ willSet{
print("set value") } didSet{
print("did set value") } }
五:方法
方法这里我们就说一点,这个感觉是很基础的了,函数方法,说多了也没意思。
使用static 或者 class 修饰的方法属于该类型的类方法,是可以使用该类型本身来调用。class 一般是在类里面修饰, static 一般用在结构体和枚举中修饰。
六:下标
所有的Swift 类型(结构体、枚举、类)都支持定义下标,下标可以作为访问对象,集合或者序列的简化方式。
Swift使用 subscript 关键字定义下标。
看下面这个例子就明白它的作用了:
struct TimesTable { let multiplier: Int subscript(index: Int) ->Int { return multiplier * index } } // 在另外的方法里面这样调用,看输出的结果 let threeTimesTable = TimesTable(multiplier: 3) print("sixtimes three is (threeTimesTable[6])") // prints"six times three is 18"
七:可选链
Swit 的所有类型默认是不能接受nil值的,如果程序想让某种数据类型能够接受nil值,则要将这种数据类型包装成可选类型:
1:在原有类型的后面添加 ? ,这种可选类型必须强制解析才能获得被包装的值。
2:在原有类型的后面添加 ! ,这种可选类型可有Swift隐式的解析被包装的值。
其实你掌握了可选类型的使用,可选链就没什么难度了,下面具体用法下面链接讲的很清楚:
八:构造器
构造器用于完成实例的构造过程,这个过程包括为实例中的每个存储属性社会中初始值和执行必要的准备和初始化任务, 与OC的构造器不同,Swift的构造器无需显式的声明返回值的类型,也无需显式使用 return返回实例, Swift 的构造器构造出来的实例由系统隐式的返回。它的本质其实就是一个或者多个名为 init 的函数。
九:可能失败的构造器
有些时候,枚举,结构体,类的构造可能不能成功的返回该类型的实例,比如你传入的构造器参数数据无效等等,这时候就定义了"可能失败的构造器"。
可能失败的构造器使用 init? 或者 init!来进行定义,在这种构造我的执行体内返回使用 return nil 来表示构造失败,该构造器返回了一个nil(缺失值)。
Swift 不允许定义两个具有相同形式类别的构造器,即使一个是可能失败的构造器,一个是普通的构造器。
后序的关于面向对象没写完的,还在制造中,有错误的地方欢迎指正,也可以加我QQ。。一起讨论学习