Swift学习笔记二
Swift是苹果公司开发的一门新语言,它当然具备面向对象的许多特性,现在开始介绍Swift中类和对象的语法。
对象和类
用"class"加上类名字来创建一个类,属性声明和声明常量或者变量是一样的,只是它是在类里边声明的而已。方法和函数声明也是一样的:
class Shape {
var numberOfSides = 0
func simpleDescription() -> String {
return "A shape with \(numberOfSides) sides."
}
}
创建类对象也很简单,注意这里没有用new关键字,类对象的属性和方法的访问方式是通过.实现的
var shape = Shape()
shape.numberOfSides = 7
var shapeDescription = shape.simpleDescription()
类的声明里边,通常都会有初始化方法init,
class NamedShape {
var numberOfSides: Int = 0
var name: String
init(name: String) {
self.name = name
}
func simpleDescription() -> String {
return "A shape with \(numberOfSides) sides."
}
}
注意这里用self来指代当前类对象,这样就区分了属性name和传入init方法的参数name。
每个属性都需要被赋值,要么在声明它的时候,或者在初始化方法中。
用deinit方法来创建解构函数,在类对象被释放之前做一些清理工作。
类的继承语法也很简单,用冒号加上父类名称就可以了。没有约定子类必须要继承自哪些根类,因此继承不是必须的。子类通过override标识覆盖父类方法。如果子类中有与父类同名的方法而没有override,则编译器会报错。编译器也会探测标识了override但是父类中又没有同名的方法。
class Square: NamedShape {
var sideLength: Double
init(sideLength: Double, name: String) {
self.sideLength = sideLength
super.init(name: name)
numberOfSides = 4
}
func area() -> Double {
return sideLength * sideLength
}
override func simpleDescription() -> String {
return "A square with sides of length \(sideLength)."
}
}
let test = Square(sideLength: 5.2, name: "my test square")
test.area()
test.simpleDescription()
简单属性可以直接保存,属性也可以有存取器:
class EquilateralTriangle: NamedShape {
var sideLength: Double = 0.0
init(sideLength: Double, name: String) {
self.sideLength = sideLength
super.init(name: name)
numberOfSides = 3
}
var perimeter: Double {
get {
return 3.0 * sideLength
}
set {
sideLength = newValue / 3.0
}
}
override func simpleDescription() -> String {
return "An equilateral triangle with sides of length \(sideLength)."
}
}
var triangle = EquilateralTriangle(sideLength: 3.1, name: "a triangle")
println(triangle.perimeter)
triangle.perimeter = 9.9
println(triangle.sideLength)
在setter中,新值的名称隐式地是newValue,也可以在set后显示地指明别的名称。
如果你的属性不需要计算,但是在设定值之前或者之后仍然需要写一些逻辑,可以用willSet和didSet,比如,下边的类就确保它的三角形的边长和正方形的边长始终相等:
class TriangleAndSquare {
var triangle: EquilateralTriangle {
willSet {
square.sideLength = newValue.sideLength
}
}
var square: Square {
willSet {
triangle.sideLength = newValue.sideLength
}
}
init(size: Double, name: String) {
square = Square(sideLength: size, name: name)
triangle = EquilateralTriangle(sideLength: size, name: name)
}
}
var triangleAndSquare = TriangleAndSquare(size: 10, name: "another test shape")
println(triangleAndSquare.square.sideLength)
println(triangleAndSquare.triangle.sideLength)
triangleAndSquare.square = Square(sideLength: 50, name: "larger square")
println(triangleAndSquare.triangle.sideLength)
类的方法和一般函数有一个很重要的区别。一般函数的参数名只在函数内部被用到,但是类方法的参数名在你调用方法的时候也被用到了(第一个参数除外)。默认情况下,当你调用某个方法的时候,该方法与其内部都有相同的参数名。你可以指定另外的名称,这个名称将在方法内部使用:
class Counter {
var count: Int = 0
func incrementBy(amount: Int, numberOfTimes times: Int) {
count += amount * times
}
}
var counter = Counter()
counter.incrementBy(2, numberOfTimes: 7)
当处理可省略变量的时候,可以在运算比如属性、方法、下标操作之前加上问号。如果问号之前的值是nil,问号之后的所有表达式被忽略掉,整个表达式的值也是nil。否则,可省略值被展开,问号之后的所有表达式都基于展开的可省略值。无论如何,整个表达式的值都是可省略值。
let optionalSquare: Square? = Square(sideLength: 2.5, name: "optional square")
let sideLength = optionalSquare?.sideLength
枚举类型和结构体
用enum来创建枚举类型变量。像类和其他类型一样,枚举类型也可以有与之相应的方法:
enum Rank: Int {
case Ace = 1
case Two, Three, Four, Five, Six, Seven, Eight, Nine, Ten
case Jack, Queen, King
func simpleDescription() -> String {
switch self {
case .Ace:
return "ace"
case .Jack:
return "jack"
case .Queen:
return "queen"
case .King:
return "king"
default:
return String(self.rawValue)
}
}
}
let ace = Rank.Ace //Enum Value
let aceRawValue = ace.rawValue //1
在上边的例子里,枚举类型变量Rank的原始类型(raw-type)是Int类型,因此只需要给第一个值赋值,剩下的值会一次自动赋予。也可以把枚举变量的原始类型设定为字符串或者浮点数,用rawValue来获取枚举变量的原始值。用init?(rawValue:)初始化器从一个原始值创建一个枚举类型的实例。
if let convertedRank = Rank(rawValue: ) {
let threeDescription = convertedRank.simpleDescription()
}
枚举类型的成员值就是实际的值,并不是原始值(raw value)的另一种书写方式,事实上,并没有所谓的真正意义上的原始值,并不需要为每个枚举类型成员赋原始值
enum Suit {
case Spades, Hearts, Diamonds, Clubs
func simpleDescription() -> String {
switch self {
case .Spades:
return "spades"
case .Hearts:
return "hearts"
case .Diamonds:
return "diamonds"
case .Clubs:
return "clubs"
}
}
}
let hearts = Suit.Hearts
let heartsDescription = hearts.simpleDescription()
注意这里用了两种引用枚举类型实例的成员值的方式:当把它作为值复制给常量hearts时,是用的显示地指明全称Suit.Hearts,因为常量没有隐式地指明类型;而在switch内部,枚举类型的成员值是用简写方式.Hearts被引用的,这是因为self的类型已经是已知合适的类型了。在任何变量类型已知并且合适的时候,都可以使用这种简写方式。
结构体
用struct关键字来创建结构体,结构体支持很多类的行为,包括方法和初始化器。结构体和类最大的区别在于当在代码里传递的时候,结构体永远是被拷贝的,而类只传递了引用。
struct Card {
var rank: Rank
var suit: Suit
func simpleDescription() -> String {
return "The \(rank.simpleDescription()) of \(suit.simpleDescription())" //在字符串中直接引用表达式或者变量
}
}
let threeOfSpades = Card(rank: .Three, suit: .Spades) //注意这种简写形式,是因为rank和suit的变量类型都已经确定了
let threeOfSpadesDescription = threeOfSpades.simpleDescription()
枚举类型成员的实例可以拥有和实例关联的值(associated value),枚举类型成员的不同实例可以有不同的值和它们相关联,这些关联值是在创建实例的时候提供的。
关联值(associated value)和原始值(raw value)是不同的:枚举类型成员的原始值对所有实例而言是相同的,在定义该枚举类型的时候就需要给出原始值。
举个栗子,在向一个服务器请求日出和日落时间的数据,服务器的返回分为两种情况:返回相应的时间或者返回一个错误
enum ServerResponse {
case Result(String, String)
case Error(String)
}
let success = ServerResponse.Result("6:00 am", "8:09 pm")
let failure = ServerResponse.Error("Out of cheese.")
switch success {
case let .Result(sunrise, sunset):
let serverResponse = "Sunrise is at \(sunrise) and sunset is at \(sunset)."
case let .Error(error):
let serverResponse = "Failure... \(error)"
}
注意sunrise和sunset是如何作为匹配switch的case的一部分从ServerResponse中被取出的。
Swift学习笔记二的更多相关文章
- 【swift学习笔记】二.页面转跳数据回传
上一篇我们介绍了页面转跳:[swift学习笔记]一.页面转跳的条件判断和传值 这一篇说一下如何把数据回传回父页面,如下图所示,这个例子很简单,只是把传过去的数据加上了"回传"两个字 ...
- WPF的Binding学习笔记(二)
原文: http://www.cnblogs.com/pasoraku/archive/2012/10/25/2738428.htmlWPF的Binding学习笔记(二) 上次学了点点Binding的 ...
- AJax 学习笔记二(onreadystatechange的作用)
AJax 学习笔记二(onreadystatechange的作用) 当发送一个请求后,客户端无法确定什么时候会完成这个请求,所以需要用事件机制来捕获请求的状态XMLHttpRequest对象提供了on ...
- [Firefly引擎][学习笔记二][已完结]卡牌游戏开发模型的设计
源地址:http://bbs.9miao.com/thread-44603-1-1.html 在此补充一下Socket的验证机制:socket登陆验证.会采用session会话超时的机制做心跳接口验证 ...
- JMX学习笔记(二)-Notification
Notification通知,也可理解为消息,有通知,必然有发送通知的广播,JMX这里采用了一种订阅的方式,类似于观察者模式,注册一个观察者到广播里,当有通知时,广播通过调用观察者,逐一通知. 这里写 ...
- java之jvm学习笔记二(类装载器的体系结构)
java的class只在需要的时候才内转载入内存,并由java虚拟机的执行引擎来执行,而执行引擎从总的来说主要的执行方式分为四种, 第一种,一次性解释代码,也就是当字节码转载到内存后,每次需要都会重新 ...
- Swift学习笔记(一)搭配环境以及代码运行成功
原文:Swift学习笔记(一)搭配环境以及代码运行成功 1.Swift是啥? 百度去!度娘告诉你它是苹果最新推出的编程语言,比c,c++,objc要高效简单.能够开发ios,mac相关的app哦!是苹 ...
- Java IO学习笔记二
Java IO学习笔记二 流的概念 在程序中所有的数据都是以流的方式进行传输或保存的,程序需要数据的时候要使用输入流读取数据,而当程序需要将一些数据保存起来的时候,就要使用输出流完成. 程序中的输入输 ...
- 《SQL必知必会》学习笔记二)
<SQL必知必会>学习笔记(二) 咱们接着上一篇的内容继续.这一篇主要回顾子查询,联合查询,复制表这三类内容. 上一部分基本上都是简单的Select查询,即从单个数据库表中检索数据的单条语 ...
随机推荐
- liunx下mysql数据库使用之三范式,关系模型设计注意项,安装目录结构
数据库的三范式第一范式===>每行记录的属性,是原子的,拆到不可拆为止.===>例如:一个人的籍贯,可以拆分为,省,市,县,乡,村 第二范式===>每行记录的非主属性(非主键属性), ...
- addView的误区
如果在代码中动态使用addView(v),那么v里头所有在xml里设置好的layout_xxx全部失效!
- Hie with the Pie(POJ 3311状压dp)
题意:披萨店给n个地方送披萨,已知各地方(包括披萨店)之间花费的时间,求送完所有地方并回到店花费的最小时间 分析:状态好确定dp[i][j],i中1表示地方已送过,否则为0,j为当前状态最后一个送过的 ...
- PICT实现组合测试用例(一)
最近阅读了史亮老师的<软件测试实战:微软技术专家经验总结>一书,其中“测试建模”一章让我受益匪浅.想想以前的测试有多久没有花过心思放在测试用例的设计上了,一直强调“测试思想”的培养也都只是 ...
- [LeetCode] Container With Most Water 简要分析
前言 这题非要说贪心的话也算是吧,不过最主要的特征还是双指针.LC的题好像不少都是扔倆头尾指针然后遍历一遍完事儿的.这道题倒是“短板效应”的不错体现了. 题目 题目链接 Given n non-neg ...
- [转]虚方法(virtual)和抽象方法(abstract)的区别
虚方法和抽象方法都可以供派生类重写,它们之间有什么区别呢? 1. 虚方法必须有实现部分,抽象方法没有提供实现部分,抽象方法是一种强制派生类覆盖的方法,否则派生类将不能被实例化.如: //抽象方法pub ...
- matlab中的字符串数组与函数调用
1, matlab中的字符串就是1维字符数组,即如: a = 'dddssd'; b = 'lsde'; c = [a, b]; 当然也可以: c= strcat(a, b); 2, matlab中的 ...
- emacs资源
当clone github时若连接不上,可以使用http代理,形如:export http_proxy=61.172.249.94:80一年成为emacs高手: https://github ...
- TCL/Expect交互式自动化测试概要 - - ITeye技术网站
TCL/Expect交互式自动化测试概要 - - ITeye技术网站 expect是一种基于TCL,能与交互式程序进行"可程序化"会话的脚本语言,是一种可以提供"分支和嵌 ...
- RHEL6.4 KVM 桥接上网的设置
关闭网络管理器 chkconfig NetworkManager off ##和桥接有冲突,要关闭 service NetworkManager stop 修改eth0为物理网口,br0为桥接网 ...