【Swift4.0】类和结构体

翻译能力有限,如有不对的地方,还请见谅!希望对Swift的学习者有所帮助微笑,使用的编写工具:JQNote InNote(iPhone)


存储属性

一个存储属性是一个常量或者变量,被存储作为一个类或者结构体实例的一部分。你可以在定义它的时候给它一个缺省值,也可以在初始化方法中设置和修改存储属性的初始化值,即便是该存储属性是常量。如果你创建了一个常量结构体实例,那么就不能修改该实例的属性,即使属性被声明为变量。


let rangeOfFourItems = FixedLengthRange(firstValue: 0, length: 4)

// this range represents integer values 0, 1, 2, and 3

rangeOfFourItems.firstValue = 6

// this will report an error, even though firstValue is a variable property”


因为结构体是值类型,当一个结构体实例被声明为常量,那么它的所有属性都不能被改变。但是对于类来说,是引用类型,如果类实例被声明为常量,你还可以改变它的变量属性的。


懒存储属性

这种属性直到它第一次被使用才会初始化。在声明存储属性前面加上lazy关键字就表示为懒存储属性。


你必须总是声明懒存储属性为变量(var),因为直到实例初始化完成之后,它的初始化值可能不能被获取,而常量属性必须总是在实例初始化完成之前有一个值。


class DataImporter {

    /*DataImporter is a class to import data from an external ”

“file.

     The class is assumed to take a non-trivial amount of time to initialize.

     */


    var filename = "data.txt"

    // the DataImporter class would provide data importing functionality here

}

 

class DataManager {

    lazy var importer = DataImporter()

    var data = [String]()

    // the DataManager class would provide data management functionality here

}

 

let manager = DataManager()

manager.data.append("Some data")

manager.data.append("Some more data")”


如上面的例子,因为importer 被声明为一个lazy 属性,DataImporter实例仅仅是当 importer属性第一次被调用获取的时候,才会创建。

print(manager.importer.filename)

// the DataImporter instance for the importer property has now been created

// Prints "data.txt”


计算型属性

计算型属性实际上不会存储一个值,相反,它们提供了一个getter和一个可选的setter方法来直接获取或者设置其它属性的值。

struct Point {

    var x = 0.0, y = 0.0

}


struct Size {

    var width = 0.0, height = 0.0

}


struct Rect {

    var origin = Point()

    var size = Size()

    var center: Point {

        get {

            let centerX = origin.x + (size.width / 2)

            let centerY = origin.y + (size.height / 2)

            return Point(x: centerX, y: centerY)

        }

        set(newCenter) {

            origin.x = newCenter.x - (size.width / 2)

            origin.y = newCenter.y - (size.height / 2)

        }

    }

}


var square = Rect(origin: Point(x: 0.0, y: 0.0),

                  size: Size(width: 10.0, height: 10.0))

let initialSquareCenter = square.center

square.center = Point(x: 15.0, y: 15.0)


只读的计算型属性

一个计算型的属性,如果只有getter方法,没有setter方法,那就被认为是一个只读的计算属性。你可以声明一个简单的只读计算属性,不需要get关键字:

struct Cuboid {

    var width = 0.0, height = 0.0, depth = 0.0

    var volume: Double {

        return width * height * depth

    }

}


let fourByFiveByTwo = Cuboid(width: 4.0, height: 5.0, depth: 2.0)

print("the volume of fourByFiveByTwo is \(fourByFiveByTwo.volume)")

// Prints "the volume of fourByFiveByTwo is 40.0”


属性观察者

属性观察者观察和响应一个属性值的改变。当属性值每次被set的时候,观察者都会被调用,即使新的值和当前的值相同。除了lazy属性,你可以将属性观察者添加到任何存储属性:


>> willSet :值被存储之前调用

>> didSet :新值被存储之后调用


当你实现了willSet,它会传递一个新的值作为一个常量参数。你也可以给这个参数特定一个名字。如果你没有写这个参数名,那么默认newValue可以被使用。类似,如果实现了didSet,你也可以特定一个参数名或者使用默认的oldValue。

class StepCounter {

    var totalSteps: Int = 0 {

        willSet(newTotalSteps) {

            print("About to set totalSteps to \(newTotalSteps)")

        }

        didSet {

            if totalSteps > oldValue  {

                print("Added \(totalSteps - oldValue) steps")

            }

        }

    }

}


类型属性

实例属性属于某个类型的实例,每次在创建实例的时候,它有自己的一系列属性。与其它实例是分开的。

你也可以定义属于类型自己的属性,而不属于每个该类型的实例。类型属性只会拷贝一次,无论该类型被创建了多少个实例。

不像存储实例属性,存储类型属性必须赋一个缺省值,这是因为类型自己没有一个初始化器可以在初始化的时候给类型属性设置值。

定义一个类型属性,使用staic关键字:

struct SomeStructure {

    static var storedTypeProperty = "Some value."

    static var computedTypeProperty: Int {

        return 1

    }

}

enum SomeEnumeration {

    static var storedTypeProperty = "Some value."

    static var computedTypeProperty: Int {

        return 6

    }

}

class SomeClass {

    static var storedTypeProperty = "Some value."

    static var computedTypeProperty: Int {

        return 27

    }

    class var overrideableComputedTypeProperty: Int {

         return 107

    }

}


获取和设置类型属性:

print(SomeStructure.storedTypeProperty)

// Prints "Some value."

SomeStructure.storedTypeProperty = "Another value."

print(SomeStructure.storedTypeProperty)

// Prints "Another value."

print(SomeEnumeration.computedTypeProperty)

// Prints "6"

print(SomeClass.computedTypeProperty)

// Prints "27”




类和结构体具有通用性和灵活的结构,是构建程序的代码块。你可以通过使用与常量,变量和函数一样的语法,定义属性和方法为你的类和结构体添加功能。不像其它程序语言,Swift不要求你为自定义的类和结构体单独创建接口和文件。在Swift中, 定义一个类或者一个结构体是在一个单独文件中,并且外部接口是自动可被其它代码调用的。


Swift中的类和结构体有许多相同点:


>> 定义属性

>> 定义方法

>> 定义下标,可使用下标来存取他们的值

>> 定义初始化方法

>> 可被扩展

>> 遵从协议


类有一些结构体所没有的能力:


>> 继承

>> 类型转化,可以在运行时检查和解析某个类实例的类型。

>> 析构器

>> 引用计数


类和结构体有相似的定义与法,类使用class关键字,结构体使用struct关键字


class SomeClass {

    // class definition goes here

}

struct SomeStructure {

    // structure definition goes here

}


例如:

struct Resolution {

    var width = 0

    var height = 0

}

class VideoMode {

    varresolution =Resolution()

    varinterlaced =false

    varframeRate =0.0

    var name: String?

}


类和结构体都是用初始化方法来创建实例:

let someResolution =Resolution()

let someVideoMode =VideoMode()


所有的结构体都有一个自动生成的成员初始化器,可以初始化创建的结构体实例的成员变量:

let vga =Resolution(width:640,height: 480)


类实例没有这样的初始化器。


结构体和枚举都是值类型,当被传递给一个常量,变量,或者一个函数,它会被copy。实际上,Swift中的所有基本类型:整型,浮点数,布尔类型,字符串,数组和字典都是值类型。


let hd =Resolution(width:1920,height: 1080)

var cinema =hd


上面的例子声明了一个常量,并且使用Resolution的初始化方法给它赋值然后声明了一个变量cinema,并且赋值hd 因为是结构体,所以会把一个新的拷贝赋值给cinema  ,虽然它们有相同的widthheight,但是是两个完全不同的实例。


类是引用类型:不像值类型,引用类型在代码传递中不会进行拷贝。


let tenEighty =VideoMode()

tenEighty.resolution = hd

tenEighty.interlaced = true

tenEighty.name = "1080i"

tenEighty.frameRate = 25.0


let alsoTenEighty =tenEighty

alsoTenEighty.frameRate = 30.0


tenEightyalsoTenEighty实际指向相同的实例,它们只是不同名字,相同的实例。


print("The frameRate property of tenEighty is now\(tenEighty.frameRate)")

// Prints "The frameRate property of tenEighty is now 30.0”


因为一个类实例可能会被多个常量或者变量引用,Swift提供了两个比较操作,检查是否两个常量或者变量引用了相同的实例:


>> 相同(===)

>> 不相同 (!==)


if tenEighty ===alsoTenEighty {

    print("tenEighty and alsoTenEighty refer to the same VideoMode instance.")

}

// Prints "tenEighty and alsoTenEighty refer to the same VideoMode instance.


注意:=== 不代表两个相等,而是说两个变量或者常量引用了相同的类实例。相等意味着两个实例在值上相等。


类和结构体都可以用来定义数据类型,然而,结构体总是值传递,类总是引用传递。这意味着它俩适合不同的任务。


>> 结构体的主要目的是集合了少部分简单相关的数据值。

>> 当传递一个结构体实例,它将被拷贝,而不是引用传递。

>> 任何结构体存储的属性都是值类型,这也将会是被拷贝,而不是引用。

>> 结构体不需要继承其它存在类型的属性或者行为。


其它情况下,使用类。实际上,大多数自定义的数据结构应该是类,而不是结构体。


Swift中,许多基本的数据类型,像String,Array,Dictionary都是用结构体实现的。这与NSString,NSArray和NSDictionary(都是类实现的,而不是结构体)不同。


一旦声明一个结构体为常量,那么它的属性都不能被修改,即使属性被声明为变量。类不同,类实例赋给一个常量,它声明的变量属性是可以被修改的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值