您的位置:首页 > 移动开发 > Swift

swift学习笔记8 类与结构

2017-04-18 13:43 232 查看

类与结构

Unlike other programming languages, Swift does not require you to create separate interface and implementation files for custom classes and structures. In Swift, you define a class or a structure in a single file, and the external interface to that class or structure is automatically made available for other code to use.

swift跟其他编程语言不一样,swift并不要求你为类和结构分别创建接口和实现实现文件。在swift中,你只需在一个文件中定义类和结构,并且该类和结构的拓展接口对于其他代码来说是可用的。

Classes and structures in Swift have many things in common. Both can:

Define properties to store values

Define methods to provide functionality

Define subscripts to provide access to their values using subscript syntax

Define initializers to set up their initial state

Be extended to expand their functionality beyond a default implementation

Conform to protocols to provide standard functionality of a certain kind

类与结构的相同点:

定义要存储值的属性

定义方法

定义获取方法

定义初始化方法

可拓展

能实现协议

Classes have additional capabilities that structures do not:

Inheritance enables one class to inherit the characteristics of another.

Type casting enables you to check and interpret the type of a class instance at runtime.

Deinitializers enable an instance of a class to free up any resources it has assigned.

Reference counting allows more than one reference to a class instance.

类具有以下结构没有的功能:

继承,类能继承。

类型转换, 你能在运行时检查和解析类实例的类型。

析构,类实例能释放它被赋予的资源。

引用计数,类实例可以有多个引用。

Structures are always copied when they are passed around in your code, and do not use reference counting.

结构在传递时都是被拷贝的,不用引用计数。

语法定义

Classes and structures have a similar definition syntax. You introduce classes with the class keyword and structures with the struct keyword. Both place their entire definition within a pair of braces

类和结构的定义语法比较相似。类定义用class 引导,结构定义用struct引导。都用大括号括起:

class SomeClass {
// 类定义
}
struct SomeStructure {
// 结构定义
}


一个例子:

struct Resolution {
var width = 0
var height = 0
}
class VideoMode {
var resolution = Resolution()
var interlaced = false
var frameRate = 0.0
var name: String?
}


结构和枚举都是值类型

类是引用类型

属性

延迟存储属性

A lazy stored property is a property whose initial value is not calculated until the first time it is used. You indicate a lazy stored property by writing the lazy modifier before its declaration.

延迟存储属性是指一个属性的初始值只有在它第一次被使用时才计算。

在属性前加上lazy关键字表明这是个延迟存储属性。

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 属性 的DataImporter 实例还没被创建

print(manager.importer.filename)
// importer 属性 的DataImporter 实例现在才被创建
// Prints "data.txt"


计算属性

In addition to stored properties, classes, structures, and enumerations can define computed properties, which do not actually store a value. Instead, they provide a getter and an optional setter to retrieve and set other properties and values indirectly.

除了存储属性之外,类,结构和枚举还可以定义计算属性,计算属性并不保存值。而是提供一个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)
print("square.origin is now at (\(square.origin.x), \(square.origin.y))")
// Prints "square.origin is now at (10.0, 10.0)"


快速声明setter方法

If a computed property’s setter does not define a name for the new value to be set, a default name of newValue is used. Here’s an alternative version of the Rect structure, which takes advantage of this shorthand notation:

如果一个计算属性的setter方法没有为新的值定义一个名字,那么就使用默认的名字newValue.

举个例子:

struct AlternativeRect {
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 {
origin.x = newValue.x - (size.width / 2)
origin.y = newValue.y - (size.height / 2)
}
}
}


只读的计算属性

A computed property with a getter but no setter is known as a read-only computed property. A read-only computed property always returns a value, and can be accessed through dot syntax, but cannot be set to a different value.

一个只有getter方法没有setter方法的计算属性称为只读的计算属性。

一个只读的计算属性永远要返回一个值,并且可以通过点语法获取,但是不能设为其他值。

You must declare computed properties—including read-only computed properties—as variable properties with the var keyword, because their value is not fixed. The let keyword is only used for constant properties, to indicate that their values cannot be changed once they are set as part of instance initialization.

计算属性–包括只读计算属性—都必须声明为变量属性,用var关键字修饰,因为它们的值是不固定的。只有常量属性才能用let关键字修饰,表明它们的值一旦被作为实例初始化的一部分进行设置之后,便不可更改了。

You can simplify the declaration of a read-only computed property by removing the get keyword and its braces:

要想声明一个只读的计算属性,只需要去掉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"


属性观察者

Property observers observe and respond to changes in a property’s value. Property observers are called every time a property’s value is set, even if the new value is the same as the property’s current value.

属性观察者观察并响应属性值的改变。 每次属性值被设置的时候都会调用属性观察者,即使新的值跟属性的当前值一样。

You can add property observers to any stored properties you define, except for lazy stored properties. You can also add property observers to any inherited property (whether stored or computed) by overriding the property within a subclass. You don’t need to define property observers for nonoverridden computed properties, because you can observe and respond to changes to their value in the computed property’s setter.

你可以给你定义的任何存储属性加上属性观察者,除了延迟存储属性。

你还可以给继承的属性(不管是存储属性还是计算属性)添加属性观察者,只需要在子类重写该属性。

你不需要为非重写的计算属性定义属性观察者,因为你可以在计算属性的setter方法中观察 和响应它们的值修改。

You have the option to define either or both of these observers on a property:

你可以定义一个或两个属性观察者

willSet is called just before the value is stored.

didSet is called immediately after the new value is stored.

在值被存储前调用willSet

值被存储后马上会调用didSet

If you implement a willSet observer, it’s passed the new property value as a constant parameter. You can specify a name for this parameter as part of your willSet implementation. If you don’t write the parameter name and parentheses within your implementation, the parameter is made available with a default parameter name of newValue.

如果你实现了willSet观察者方法,它会把新的属性值当作一个常量参数传入。你可以为此参数起个名字。如果你不写此参数的名字和括号,那么此参数的名字为默认的参数名newValue。

Similarly, if you implement a didSet observer, it’s passed a constant parameter containing the old property value. You can name the parameter or use the default parameter name of oldValue. If you assign a value to a property within its own didSet observer, the new value that you assign replaces the one that was just set.

同样的,如果你实现了didSet观察者方法,它会把旧属性的值作为常量参数传入。你可以自己命名该参数或使用默认的参数名oldValue。如果你在一个参数自己的didSet观察者方法里给该参数赋值,那么你赋予的新值将会把刚刚设置的值替换掉。

举个例子

class StepCounter {
var totalSteps: Int = 0 {
willSet(newTotalSteps) {
print("About to set totalSteps to \(newTotalSteps)")
}
didSet {
if totalSteps > oldValue  {
print("Added \(totalSteps - oldValue) steps")
}
}
}
}
let stepCounter = StepCounter()
stepCounter.totalSteps = 200
// About to set totalSteps to 200
// Added 200 steps
stepCounter.totalSteps = 360
// About to set totalSteps to 360
// Added 160 steps
stepCounter.totalSteps = 896
// About to set totalSteps to 896
// Added 536 steps


类型属性

Instance properties are properties that belong to an instance of a particular type. Every time you create a new instance of that type, it has its own set of property values, separate from any other instance.

实例属性属于一个实例。每次你创建一个实例,它就拥有它自己的属性值,与其他的实例区分开。

You can also define properties that belong to the type itself, not to any one instance of that type. There will only ever be one copy of these properties, no matter how many instances of that type you create. These kinds of properties are called type properties.

你也可以自己定义属于那个类型的属性,这个属性不属于任何该类型的实例。这种属性只有一份拷贝,不管你创建了多少这个类型的实例。这种属性称为类型属性。

Type properties are useful for defining values that are universal to all instances of a particular type, such as a constant property that all instances can use (like a static constant in C), or a variable property that stores a value that is global to all instances of that type (like a static variable in C).

类型属性对于为一个类的所有实例都有的属性定义值时非常有用,所有的实例可以像常量属性一样使用它(类似c的静态常量),或者是一个存储了全局变量的变量属性(类似c中的静态变量);

类型属性语法

You define type properties with the static keyword. For computed type properties for class types, you can use the class keyword instead to allow subclasses to override the superclass’s implementation.

用static关键字定义类型属性。对于类的计算属性,可以使用class关键字,这可以使得子类可以重写父类的实现。

举个例子

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
}
}


方法

结构和枚举能定义方法,是swift跟c oc之间很大的一个不同。在oc中,方法只能由类定义。

实例方法

Instance methods are functions that belong to instances of a particular class, structure, or enumeration.

实例方法属于类,结构或者枚举的实例。

举个例子:

class Counter {
var count = 0
func increment() {
count += 1
}
func increment(by amount: Int) {
count += amount
}
func reset() {
count = 0
}
}


Counter类定义了三个实例方法:

increment() 把count加1

increment(by: Int) 把count加上一个指定的整数值amount

reset() 重设count为0

使用方式如下:

let counter = Counter()
// the initial counter value is 0
counter.increment()
// the counter's value is now 1
counter.increment(by: 5)
// the counter's value is now 6
counter.reset()
// the counter's value is now 0


self属性

struct Point {
var x = 0.0, y = 0.0
func isToTheRightOf(x: Double) -> Bool {
return self.x > x
}
}
let somePoint = Point(x: 4.0, y: 5.0)
if somePoint.isToTheRightOf(x: 1.0) {
print("This point is to the right of the line where x == 1.0")
}
// Prints "This point is to the right of the line where x == 1.0"


在实例方法内修改值类型

Structures and enumerations are value types. By default, the properties of a value type cannot be modified from within its instance methods.

结构和枚举都是值类型。默认地,值类型的属性在它的实例方法中不能被修改。

However, if you need to modify the properties of your struc
ad86
ture or enumeration within a particular method, you can opt in to mutating behavior for that method. The method can then mutate (that is, change) its properties from within the method, and any changes that it makes are written back to the original structure when the method ends. The method can also assign a completely new instance to its implicit self property, and this new instance will replace the existing one when the method ends.

但是,如果你需要在一个方法中修改结构或枚举的属性,你可以为那个方法选择使用mutating的行为。那个方法就可以在方法内修改它的属性,它所做的修改会在方法结束之后写回到初始的结构。这个方法把新的实例赋给它的隐式的self属性,这个新的实例会在方法结束时把原来的替换掉。

You can opt in to this behavior by placing the mutating keyword before the func keyword for that method:

这种方法要在前面写上mutating关键字;

struct Point {
var x = 0.0, y = 0.0
mutating func moveBy(x deltaX: Double, y deltaY: Double) {
x += deltaX
y += deltaY
}
}
var somePoint = Point(x: 1.0, y: 1.0)
somePoint.moveBy(x: 2.0, y: 3.0)
print("The point is now at (\(somePoint.x), \(somePoint.y))")
// Prints "The point is now at (3.0, 4.0)"


Note that you cannot call a mutating method on a constant of structure type, because its properties cannot be changed, even if they are variable properties,

注意,不能对常量结构类型调用修改(mutating)方法,因为它们的属性不能改变,即使它们是变量属性。

let fixedPoint = Point(x: 3.0, y: 3.0)
fixedPoint.moveBy(x: 2.0, y: 3.0)
// 这会报错


在修改方法(mutating)中给self赋值

举个例子

struct Point {
var x = 0.0, y = 0.0
mutating func moveBy(x deltaX: Double, y deltaY: Double) {
self = Point(x: x + deltaX, y: y + deltaY)
}
}


This version of the mutating moveBy(x:y:) method creates a brand new structure whose x and y values are set to the target location. The end result of calling this alternative version of the method will be exactly the same as for calling the earlier version.

这个版本的moveBy(x:y:)方法创建了一个全新的结构,它的x和y值被设置为目标位置。调用这个方法得到的结果和调用之前的方法得到的结果完全一致。

Mutating methods for enumerations can set the implicit self parameter to be a different case from the same enumeration:

枚举的修改方法可以在枚举中把隐式的self参数设置为一个不同的case:

enum TriStateSwitch {
case off, low, high
mutating func next() {
switch self {
case .off:
self = .low
case .low:
self = .high
case .high:
self = .off
}
}
}
var ovenLight = TriStateSwitch.low
ovenLight.next()
// ovenLight 现在的值是 .high
ovenLight.next()
// ovenLight 现在的值是 .off
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  swift ios ios开发