官文:从今天开始开发iOS应用(Swift)第一章4~5节纯中文

来源:互联网 发布:matlab和python 编辑:程序博客网 时间:2024/06/05 00:38

1.4 Functions and Methods:函数和方法

1.4.1 函数(function)

函数:指的是一段有名字的,可重用的代码段。它可被用在程序中的许多地方。

使用func来声明一个函数(function)。函数可包含0到多个参数,以”名字:类型”的格式书写。函数参数的作用是当函数调用时,可传递更多的信息到函数中。函数也可以有返回值,写在“->”后面。返回值的作用是当函数调用结束时,返回函数调用的结果。而函数的实现则是写在大括号内:

func greet(name: String, day: String) -> String {    return "Hello \(name), today is \(day)."}

使用函数名后面跟上参数列表的形式来调用函数,只有第一个参数不用写参数名:

greet("Anna", day: "Tuesday")greet("Bob", day: "Friday")greet("Charlie", day: "a nice day")

1.4.2 方法(method)

在一个特定类中定义的函数称为方法(method)。方法被显式绑定到该特定类上,也只能被该类所调用(或是该类型的子类)。在之前的例子中,有一个String类型的方法:hasSuffix(),如下所示:

let exampleString = "hello"if exampleString.hasSuffix("lo") {    print("ends in lo")}

如你所见,使用点操作符“.”来调用该类型中的方法。

调用时第一个参数省略参数名,其余各个参数都必须写上名称。例如下面代码中,该方法有两个参数,只写出第二个参数的名称“atIndex:”(代码可读性得到很大提升):

var array = ["apple", "banana", "dragonfruit"]array.insert("cherry", atIndex: 2)array

1.5 Classes and Initializers:类和构造器

在面向对象编程中,程序活动大多都依赖于程序内部对象之间的交互。

对象(object):是类的实例化产物。

类(class):可以理解为是该对象的蓝图。

在类中使用属性(property)来存储它自身的额外信息,并且由方法(method)来定义它的行为。

1.5.1 类的定义

使用class后面跟上类名来定义一个类。而类属性的声明语法和常量变量的声明语法类似,不同之处仅在于它们是在类中声明的。类中方法的声明和函数声明类似。

下面的代码中声明了一个Shape类,它有一个numberOfSides属性,并且有一个simpleDescription()方法:

class Shape{    var numberOfSides = 0    func simpleDescription() -> String    {        return "A shape with \(numberOfSides) sides."    }}

1.5.2 对象的定义及访问

创建一个类的实例,即创建一个对象

创建方法是在类名之后加上括号“()”,使用点操作符来访问所创建的实例的属性和方法。这里,shape是一个Shape类实例化出来的对象:

var shape = Shape()shape.numberOfSides = 7var shapeDescription = shape.simpleDescription()

1.5.3 构造器(initializer)

Shape类中还缺少一个重要内容:构造器(initializer)。

构造器实际是类的方法,它可用于初始化类的实例对象。包括初始化所有属性,以及完成一些其他的初始化工作。

您可以使用init来创建一个构造器。

下面例子中定义了一个NamedShape类,它含有一个构造器,构造器接收一个name参数:

class NamedShape{    var numberOfSides = 0    var name: String    init(name: String)    {        self.name = name    }    func simpleDescription() -> String    {        return "A shape with \(numberOfSides) sides."    }}

这里使用self关键字来区分类的属性名name和构造器参数名name

所有的属性都需要被赋值(在声明时赋值,或是在构造器中进行赋值)。

在类名后面加上括号来调用构造器,而不需要使用init来调用它。当调用构造器时,需要写出所有的参数名,如下所示:

let namedShape = NamedShape(name: "my named shape")

1.5.4 类的继承(inherit)和方法覆盖(override)

通过继承(inherit),一个类可以拥有另外一个类行为。被继承的类称为父类(superclass),而继承了父类行为的类称为子类(subclass)。继承的语法格式为:子类名:父类名。一个子类只能继承一个父类,以此类推,从而构成了一个树状的继承层次关系。

子类中的方法覆盖父类中同名方法时,需要写上override,若在覆盖时不写override,则编译器会报错。另外,编译器也会检查那些写了override的,但实际上并没有覆盖父类方法的子类方法。

下面的代码中定义了Square类,它是NamedShape的子类:

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 testSquare = Square(sideLength: 5.2, name: "my test square")testSquare.area()testSquare.simpleDescription()

1.5.5 构造器的写法

需要注意,Square类的构造器进行了三个步骤:

  1. 设置Square类属性sideLength;
  2. 调用父类NamedShape的构造器;
  3. 修改父类NamedShape的属性numberOfSides。

这样可以完成更多的初始化工作。

实际上,有时需要初始化工作不总是成功,因为如果提供了超出范围的初始化参数,则会初始化出错误的对象。

有时可能会初始化对象失败的构造器称为可失效构造器(failable initializer)。一个可失效构造器有可能返回nil。使用init?来声明一个可失效构造器:

class Circle: NamedShape {    var radius: Double    init?(radius: Double, name: String) {        self.radius = radius        super.init(name: name)        numberOfSides = 1        if radius <= 0 {            return nil        }    }    override func simpleDescription() -> String {        return "A circle with a radius of \(radius)."    }}let successfulCircle = Circle(radius: 4.2, name: "successful circle")let failedCircle = Circle(radius: -7, name: "failed circle")

构造器可以有一些相关扩展。指定构造器(designated initializer)指示它是类的一个主要构造器。任何的类构造器最终都要调用指定构造器。一个快捷构造器是一个次要的构造器,它主要用于添加额外行为或进行自定义操作,但是也必须最终调用指定构造器。这主要和次要构造器分别使用designateconvenience关键字进行定义。

如果在构造器后面跟上了required关键字,则表示每一个该类的子类都必须重写该构造器。

1.5.6 对象类型转换

类型转换是一个检测对象类型的方法,即将该对象看作是它的继承层次中的另外的父类或子类对象来对待。

某类型的常量或变量可能实际是该类的子类实例(父类指针引用子类对象)。如果你遇到这样的情况,你可以尝试使用类型转换操作符将它向下类型转换为子类类型。

由于向下类型转换可能会失败,故类型转换操作符有两种不同的形式。第一种是可选类型的形式,即“as?”,它返回一个你尝试转换的目标类型对应的可选类型值。第二种是强制转换形式,即“as!”,尝试转换并强制解包。

如果你认为类型转换可能会失败,则使用可选类型转换操作符“as?”。这种形式的类型转换总会返回一个可选类型结果,如果转换失败,则会返回nil。你可以通过返回结果来查看转换是否成功。

如果你确信类型转换一定成功,则可以使用强制类型转换操作符“as!”。但如果转换不成功,则这个形式的向下类型转换将导致运行时错误。

下面例子中使用可选类型转换操作符检查shape数组中的每一个shape对象是一个circle还是一个square。如果对应形状找到,则计数器加一,最后打印计数结果:

class Triangle: NamedShape {    init(sideLength: Double, name: String) {        super.init(name: name)        numberOfSides = 3    }}let shapesArray = [Triangle(sideLength: 1.5, name: "triangle1"), Triangle(sideLength: 4.2, name: "triangle2"), Square(sideLength: 3.2, name: "square1"), Square(sideLength: 2.7, name: "square2")]var squares = 0var triangles = 0for shape in shapesArray {    if let square = shape as? Square {        squares++    } else if let triangle = shape as? Triangle {        triangles++    }}print("\(squares) squares and \(triangles) triangles.")
0 0
原创粉丝点击