iOS学习笔记43-Swift(三)类
一、Swift的类class
作为一门面向对象语言,类也是Swift的非常重要的类型,我们先来看下一个简单的类
//Swift中一个类可以不继承于任何其他基类,那么此类本身就是一个基类
class Person {
//定义属性
var name:String
var height = 0.0
//构造器方法,注意如果不编写构造方法默认会自动创建一个无参构造方法
init(name:String){
self.name = name
}
//析构器方法,在对象被释放时调用,类似于ObjC的dealloc,注意这里没有括号和参数,无法直接调用
deinit{
println("deinit...")
}
//定义对象方法
func showMessage(){
println("name=\(name),height=\(height)")
}
}
//创建类的对象
var p = Person(name: "Liuting")
p.height = 170.0
p.showMessage() //结果:name=Liuting,height=170.0
//类是引用类型
var p2 = p
p2.name = "XiaoMing"
println(p.name) //结果:XiaoMing
//“===”表示等价于,这里不能使用等于“==”,等于用于比较值相等,p和p2是不同的值,但是指向的对象相同
if p === p2 {
println("p===p2") //p等价于p2,表示二者指向同一个对象
}
二、属性
Swift中淡化了成员属性的概念,把属性分为两种:
- 存储属性:
无论从概念上还是定义方式上来看,存储属性更像其他语言中的成员变量,但是不同的是:
- 可以控制读写操作(
var
表示可读可写,let
表示只读) - 通过属性监视器来属性的变化(
willSet
、didSet
) - 快速实现懒加载功能(
lazy
修饰)
- 计算属性:
计算属性并不直接存储一个值,而是提供getter
来获取一个值,或者利用setter
来间接设置其他属性。
下面是对象属性使用实例:
class Account {
//定义存储属性,设置默认值,添加属性监听器
var balance:Double = 0.0{
//即将赋值时调用
willSet{
//注意此时修改balance的值没有用
self.balance = 2.0
//newValue表示即将赋值的新值,并且在属性监视器内部调用属性不会引起监视器循环调用
println("Account.balance willSet,newValue=\(newValue),value=\(self.balance)")
}
//赋值完成后调用
didSet{
//注意此时修改balance的值将作为最终结果
self.balance = 3.0
//oldValue表示已经赋值的旧值,并且在属性监视器内部调用属性不会引起监视器循环调用
println("Account.balance didSet,oldValue=\(oldValue),value=\(self.balance)")
}
}
}
class Person {
//firstName、lastName、age是存储属性
var firstName:String //var定义表示该存储属性可读可写
var lastName:String
let age:Int //let定义表示该存储属性只读
//属性的懒加载,第一次访问才会初始化
lazy var account = Account()//在Swift中懒加载的属性不一定就是对象类型,也可以是基本类型
//fullName是一个计算属性,在get、set方法中不能直接访问计算属性,否则会引起循环调用
var fullName:String{
//获取该计算属性时调用
get{
return firstName + "." + lastName
}
//设置该计算属性时调用
set{
//set方法中的newValue表示即将赋值的新值,这里是分割字符串
let array = split(newValue, maxSplit: Int.max,
allowEmptySlices: false,
isSeparator: {$0=="."})
if array.count == 2 {
firstName = array[0]
lastName = array[1]
}
}
}
//构造器方法,注意如果不编写构造方法默认会自动创建一个无参构造方法
init(firstName:String, lastName:String, age:Int){
self.firstName = firstName
self.lastName = lastName
self.age = age
}
//定义方法
func showMessage(){
println("name=\(self.fullName),age=\(self.age)")
}
}
//创建对象
var p = Person(firstName: "Liu", lastName: "Ting", age:22)
p.showMessage() //结果:name=Liu.Ting,age=22
p.fullName = "Liu.HAHA" //设置计算属性
p.showMessage() //结果:name=Liu.HAHA,age=22
p.account.balance = 10
/* 下面是存储属性监听器方法打印:
Account.balance willSet,newValue=10,value=0.0
Account.balance didSet,oldValue=10,value=3.0
*/
println("p.account.balance=\(p.account.balance)") //结果:p.account.balance=3.0
- 计算属性并不直接存储一个值,而是提供
getter
来获取一个值,或者利用setter
来间接设置其他属性; lazy
属性必须有初始值,必须是变量不能是常量,因为常量在构造完成之前就已经确定了值;- 在构造对象方法之前存储属性必须有值(可选类型除外),无论是变量属性还是常量属性,这个值既可以在属性创建时指定,也可以在构造方法内指定;
- 存储属性的默认值设置不会引起属性监视器的调用(另外在构造方法中赋值也不会引起属性监视器调用),只有在外部设置存储属性才会引起属性监视器调用;
除了上面的对象属性外,我们还可以定义类的属性:
class Student {
//定义类的属性只需要在前面加static关键字即可,也是分为存储属性和计算属性,这里是计算属性
static var skin:Array<String>{
//只定义了getter,表示该计算属性是只读的
get{
return ["yellow", "white", "black"]
}
}
}
//读取类的属性
for color in Student.skin {
println(color)
}
三、方法
Swift的类中的方法可分为以下几个类别:
- 构造器方法
- 默认构造器方法(当存在有参数的指定构造器方法,被覆盖)
- 指定构造器方法
- 便利构造器方法
- 析构器方法
- 对象方法
- 类方法
以下是方法使用实例:
class Person {
//定义属性
var name:String
var height:Double
var age = 0
//1.2.指定构造器方法,注意如果不编写构造方法,默认会自动创建一个无参构造方法
init(name:String, height:Double, age:Int){
self.name = name
self.height = height
self.age = age
}
//1.3.便利构造方法,通过调用指定构造方法、提供默认值来简化构造方法实现
convenience init(name:String){
self.init(name:name, height:0.0, age:0)
}
//2.析构方法,在对象被释放时调用,注意此方法没有括号,没有参数,无法直接调用
deinit{
println("deinit...")
}
//3.对象方法
func modifyInfoWithAge(age:Int, height:Double){
self.age = age
self.height = height
}
//4.类方法,使用class修饰的方法即是类方法
class func showClassName(){
println("Class name is Person")
}
}
//通过便利构造方法创建对象
var p = Person(name: "liuting")
//调用对象方法
p.modifyInfoWithAge(22,height: 170)
//调用类方法
Person.showClassName()
- 除构造方法、析构方法外,其他方法的参数默认除了第一个参数是局部参数,从第二个参数开始既是局部参数又是外部参数。但是,对于函数,默认情况下只有默认参数既是局部参数又是外部参数,其他参数都是局部参数。
- 构造方法的所有参数默认情况下既是外部参数又是局部参数
- 只有便利构造器方法才能调用当前类的指定构造方法
- 有参数的指定构造器方法会覆盖调用默认的无参构造器方法
- 一个对象被释放前,先自动调用自己的析构方法,然后一层一层往上调用父类的析构方法
四、下标脚本
下标脚本是一种访问集合的快捷方式,如果我们自定义的类具有集合类型的功能,我们可以定义下标脚本来快捷访问该类属性,定义下标脚本是通过关键字subscript
进行的。
class Record {
//定义属性,store是Record内部的存储结构,这里是字典
var store:[String:String]
//指定构造方法
init(data:[String:String]){
self.store = data
}
//下标脚本,下标索引为整形(注意也可以实现只有getter的只读下标脚本)
subscript(index:Int) -> String{
get{
//字典的key进行排序后根据Index整形索引获取字典的值
var key = sorted(Array(self.store.keys))[index]
return self.store[key]!
}
set{
//字典的key进行排序后根据Index整形索引设置字典的值
var key = sorted(Array(self.store.keys))[index]
self.store[key] = newValue //newValue和属性一样使用
}
}
//下标脚本,下标索引为字符串
subscript(key:String) -> String{
get{
return store[key]!
}
set{
store[key] = newValue
}
}
}
//创建对象
var record = Record(data:["name":"liuting","sex":"male"])
println("r[0]=\(record[0])") //结果:r[0]=liuting
record["sex"] = "female"
println(record["sex"]) //结果:female
五、继承
和ObjC一样,Swift也是单继承的(可以实现多个协议,此时协议放在后面),子类可以调用父类的属性、方法,重写父类的方法,添加属性监视器,甚至可以将只读属性重写成读写属性。
//定义一个父类
class Person {
var firstName:String
var lastName:String
var age:Int = 0
var fullName:String{
get{
return firstName + " " + lastName
}
}
//指定构造方法
init(firstName:String,lastName:String){
self.firstName = firstName
self.lastName = lastName
}
//对象方法
func showMessage(){
println("name=\(self.fullName),age=\(self.age)")
}
//通过final声明,子类无法重写
final func sayHello(){
println("hello world.")
}
}
//定义子类
class Student: Person {
//重写属性,为属性添加监视器,重写都需要加override关键字
override var firstName:String{
willSet{
println("firstName willSet")
}
didSet{
println("firstName didSet")
}
}
//添加子类属性
var score:Double
//子类指定构造方法一定要调用父类构造方法
//并且必须在子类存储属性初始化之后调用父类构造方法
init(firstName:String, lastName:String, score:Double){
self.score = score
super.init(firstName: firstName, lastName: lastName)
}
//便利构造方法
convenience init(){
self.init(firstName:"", lastName:"", score:0)
}
//将只读属性重写成了可写属性
override var fullName:String{
get{
return super.fullName;
}
set{
let array = split(newValue, maxSplit: Int.max,
allowEmptySlices: false,
isSeparator: { $0 == "." })
if array.count == 2 {
firstName = array[0]
lastName = array[1]
}
}
}
//重写对象方法
override func showMessage() {
println("name=\(self.fullName),age=\(self.age),score=\(self.score)")
}
}
//创建子类对象
var p = Student()
p.firstName = "liu"
p.showMessage() //结果:name=liu,age=0,score=0
p.fullName = "Liu.Ting"
p.showMessage() //结果:name=Liu.Ting,age=0,score=0
p.sayHello()
- 只有指定构造方法才能调用父类的构造方法。
- 如果父类中存在有参数的指定构造方法,子类的指定构造方法不会自动调用父类无参的指定构造方法。
- 如果父类仅有一个无参构造方法(不管是否包含便利构造方法),子类的构造方法默认就会自动调用父类的无参构造方法(这种情况下可以不用手动调用)。
- 常量属性只能在定义它的类的构造方法中初始化,不能在子类中初始化
- 一个对象被释放前,先自动调用自己的析构方法,然后一层一层往上调用父类的析构方法。
- 便利构造方法必须调用同一个类中的其他指定构造方法(可以是指定构造方法或者便利构造方法),不能直接调用父类构造方法。
iOS学习笔记43-Swift(三)类的更多相关文章
- IOS学习笔记2—Objective C—类、属性、方法
以下是我学习IOS开发的一些笔记和心得,贴出来和大家一同分享,也希望大家能补充和纠错,共同进步 有Android和IOS开发问题也希望能和大家交流! Objective-C 1.OC是一门基于C的面向 ...
- iOS学习笔记14-网络(三)WebView
一.WebView WebView就是一个内嵌浏览器控件,在iOS中主要有两种WebView:UIWebView和WKWebView,UIWebView是iOS2之后开始使用,WKWebView是在i ...
- iOS学习笔记06—Category和Extension
iOS学习笔记06—Category和Extension 一.概述 类别是一种为现有的类添加新方法的方式. 利用Objective-C的动态运行时分配机制,Category提供了一种比继承(inher ...
- iOS学习笔记-自定义过渡动画
代码地址如下:http://www.demodashi.com/demo/11678.html 这篇笔记翻译自raywenderlick网站的过渡动画的一篇文章,原文用的swift,由于考虑到swif ...
- iOS学习笔记——AutoLayout的约束
iOS学习笔记——AutoLayout约束 之前在开发iOS app时一直以为苹果的布局是绝对布局,在IB中拖拉控件运行或者直接使用代码去调整控件都会发上一些不尽人意的结果,后来发现iOS在引入了Au ...
- iOS学习笔记-精华整理
iOS学习笔记总结整理 一.内存管理情况 1- autorelease,当用户的代码在持续运行时,自动释放池是不会被销毁的,这段时间内用户可以安全地使用自动释放的对象.当用户的代码运行告一段 落,开始 ...
- iOS学习笔记总结整理
来源:http://mobile.51cto.com/iphone-386851_all.htm 学习IOS开发这对于一个初学者来说,是一件非常挠头的事情.其实学习IOS开发无外乎平时的积累与总结.下 ...
- iOS学习笔记之ARC内存管理
iOS学习笔记之ARC内存管理 写在前面 ARC(Automatic Reference Counting),自动引用计数,是iOS中采用的一种内存管理方式. 指针变量与对象所有权 指针变量暗含了对其 ...
- IOS学习笔记(四)之UITextField和UITextView控件学习
IOS学习笔记(四)之UITextField和UITextView控件学习(博客地址:http://blog.csdn.net/developer_jiangqq) Author:hmjiangqq ...
- iOS学习笔记之UITableViewController&UITableView
iOS学习笔记之UITableViewController&UITableView 写在前面 上个月末到现在一直都在忙实验室的事情,与导师讨论之后,发现目前在实验室完成的工作还不足以写成毕业论 ...
随机推荐
- This implementation is not part of the Windows Platform FIPS validated cryptographic algorithms while caching
今天运行自己的网站时报了这样一个错误,很是纳闷,这个网站运行了这么久,怎么报这个错呢,原来是做缓存的时候用到了基于windows平台的加密算法.解决方法如下: 删除注册表下的这个节点即可.删除HKEY ...
- 分享一些关于Lucene的心得
Lucene的概述 Lucene是一个全文搜索框架,而不是应用产品.因此它并不像http://www.baidu.com/ 或者google Desktop那么拿来就能用,它只是提供了一种工具让你能实 ...
- HDU - 5491 The Next 2015 ACM/ICPC Asia Regional Hefei Online
从D+1开始,对于一个数x,区间[x,x+lowbit(x))内的数字的二进制位上1的数量整体来说是单调不减的,因此可快速得出1在这个区间的取值范围. 每次判断一下有没有和[s1,s2]有没有交集,一 ...
- UVA 10382 Watering Grass (区间覆盖,贪心)
问题可以转化为草坪的边界被完全覆盖.这样一个圆形就换成一条线段. 贪心,从中选尽量少的线段把区间覆盖,按照把线段按左端点排序,记录一个当前已经覆盖区间的位置cur, 从左端点小于等于cur选一个右端点 ...
- EditPlus 3.7激活码注册码
EditPlus3.7激活教程以及EditPlus3.7激活码使用方法 EditPlus是一款功能齐全的文字编辑器,搭配其他的插件还可以实现很多的功能,还可以编辑和编译Java,调试程序等,主要用来打 ...
- 使用EventLog组件读写事件日志
实现效果: 知识运用: Eventlog类的SourceExists方法 //确定指定的事件源是否已在本地计算机注册 public static bool SourceExists(string s ...
- 2018.3.27 Mac 配置Tomcat
先在官网上下载Tomcat .也可以用这个传送门. https://tomcat.apache.org/download-70.cgi 选择zip文件夹的下载就ok 下载完成之后将该文件夹.(如果是t ...
- java static block
java 中 静态块的作用 (一)java 静态代码块 静态方法区别一般情况下,如果有些代码必须在项目启动的时候就执行的时候,需要使用静态代码块,这种代码是主动执行的;需要在项目启动的时候就初始化,在 ...
- IE下contentWindow对象与FF、Chrome下的区别
在ie中frame(iframe)标签通过name和id获取的对象是不同的. 通过name获取的本身就是contentWindow对象.所以 在ie中不用再找contentWindow了 例: let ...
- 常用的CSS居中方式
1.水平居中margin 0 auto;(浮动元素除外) 这个属性在网页制作的过程中是经常被用到的,一般情况下页面的版心你就可以看到它. <style> .father { width: ...