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: 3) {
    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中被取出的。

时间: 2024-08-26 22:37:33

Swift学习笔记二的相关文章

Swift学习笔记(二)参数类型

关于参数类型,在以前的编程过程中,很多时间都忽视了形参与实参的区别.通过这两天的学习,算是捡回了漏掉的知识. 在swift中,参数有形参和实参之分,形参即只能在函数内部调用的参数,默认是不能修改的,如果想要修改就需要在参数前添加var声明. 但这样的声明过后,仍旧不会改变实参的值,这样就要用到inout了,传递给inout的参数类型必须是var类型的,不能是let类型或者字面类型,(字面类型是在swift中常提的一个术语,个人认为就是赋值语句,也不能修改)而且在传递过程中,要用传值符号"&

Swift学习笔记十二:下标脚本(subscript)

下标脚本就是对一个东西通过索引,快速取值的一种语法,例如数组的a[0].这就是一个下标脚本.通过索引0来快速取值.在Swift中,我们可以对类(Class).结构体(structure)和枚举(enumeration)中自己定义下标脚本的语法 一.常规定义 class Student{ var scores:Int[] = Array(count:5,repeatedValue:0) subscript(index:Int) -> Int{ get{ return scores[index];

【Swift】学习笔记(二)——基本运算符

运算符是编程中用得最多的,其包括一元,二元和三元 三种运算符.swift也和其它编程语言一样基本就那些,下面总结一下,也有它特有的运算符,比如区间运算符 1.一元运算符 =   赋值运算符,用得最多的啦,其不带任何返回值 +  加法(数字相加,也可用于字符拼接var ss = "a"+"b") -   减法 *   乘法 /   除法 % 求余(负号忽略,浮点数也可以求余) >  大于 <  小于 2.二元运算符 ++  自增(就是i = i + i的缩

Swift学习笔记(二):属性、元组

一.属性的getter和setter //设置计算型属性:其并不真正的存储值,而是每次通过其他值计算得来 var subtotal: Double { //getter:通过total.taxPct计算获得total的值 get { return total / (taxPct + 1) } //setter:更新的是相关的值(比如此处基于newSubtotal来设置total.taxPct的值) set(newSubtotal) { //... } } 二.元组 | Tuples //创建一个

swift学习笔记之二——集合

//=========================== //2014/7/21 17:27 swift集合 //=========================== swift提供了两种集合类型,arrays和dictionaryies,两种集合都是可变的,可以在集合声明后对其进行新增.删除和修改操作. 1.array 数组的定义与java数组相同,但swift的数组提供了更灵活的创建方式和操作方式. 数组创建和初始化方式: var array1: Array<T> = [val1,va

swift学习笔记(三)关于拷贝和引用

在swift提供的基本数据类型中,包括Int ,Float,Double,String,Enumeration,Structure,Dictionary都属于值拷贝类型. 闭包和函数同属引用类型 捕获则为拷贝.捕获即定义这些常量和变量的原作用域已不存在,闭包仍然可以在闭包函数体内引用和修改这些值 class属于引用类型. Array的情况稍微复杂一些,下面主要对集合类型进行分析: 一.关于Dictionary:无论何时将一个字典实例赋给一个常量,或者传递给一个函数方法时,在赋值或调用发生时,都会

Swift学习笔记(一):基础

一.常量 & 变量 //常量 let constantsTeam = 1 //变量 var variablesTeam = 2 尽可能使用常量,这样更清晰并且内存更不容易肾亏. 二.显示/隐式指定类型 //隐式 let inferredTeam = 3 //显式 let explicitTeam:Int = 4 三.字符串输出 //通过\(变量或常量名)来引用组合字符串 println("\(inferredTeam) is bigger than \(variablesTeam)!&q

Swift学习笔记:类和结构

一.类和结构的异同 类和结构有一些相似的地方,它们都可以: 1. 定义一些可以赋值的属性: 2. 定义具有功能性的方法 3. 定义下标,使用下标语法 4. 定义初始化方法来设置初始状态 5. 在原实现方法上的可扩展性 根据协议提供某一特定类别的基本功能 1. 类还有一些结构不具备的特性: 2. 类的继承性 3. 对类实例实时的类型转换 4. 析构一个类的实例使之释放空间 5. 引用计数,一个类实例可以有多个引用 1. 定义语法 struct Name{ let firstName = "&quo

swift学习笔记(六)析构过程和使用闭包对属性进行默认值赋值

一.通过闭包和函数实现属性的默认值 当某个存储属性的默认值需要定制时,可以通过闭包或全局函数来为其提供定制的默认值. 注:全局函数结构体和枚举使用关键字static标注    函数则使用class关键字标注 当对一个属性使用闭包函数进行赋值时,每当此属性所述的类型被创建实例时,对应的闭包或函数会被调用,而他们的返回值会被作为属性的默认值. ESC: Class SomeCLass{ let someProperty:SomeType={ //给someProperty赋一个默认值 //返回一个与