感谢作者
https://www.jianshu.com/p/99c76ea439e2
// 属性
// 属性将值与特定类,结构或枚举相关联。
// 存储属性:存储值,将常量和变量值存储为实例的一部分,
// 存储属性仅由类和结构体支持。
// 通过 var 或者 let 声明
// 计算属性:计算值,计算属性由类,结构体和枚举支持。
// 结构体是值类型,当标记值类型的实例为常量时其所有属性便都会标记为常量。
// 类是引用类型,不管是使用类的变量实例还是常量实例,都可以修改变量属性的值,
// 但是不能修改常量属性的值。
//使用`var`声明StructEnumType的变量实例
var enumType = StructEnumType(constantPro: 0, varPro: 3);
//尝试修改变量属性
//enumType.constantPro = 0;
//!< 编译器报错:Cannot assign to property: 'constantPro' is a 'let' constant
//尝试修改变量属性
enumType.varPro = 6;
print(enumType);
//!< 改变成功。输出:StructEnumType(constantPro: 0, varPro: 6)
// 常量结构体实例的存储属性
//使用`let`声明StructEnumType的常量实例
let enumType2 = StructEnumType(constantPro: 0, varPro: 3);
//尝试修改变量属性
//enumType2.constantPro = 0;
//!< 编译器报错:Cannot assign to property: 'constantPro' is a 'let' constant
//尝试修改变量属性
// enumType2.varPro = 6;
//!< 编译器报错:Cannot assign to property: 'enumType' is a 'let' constant
// 懒存储属性
// 其初始值在初次使用的时候才会被调用。类似懒加载。
// 使用关键字lazy。
// 懒属性必须使用var关键字声明为变量属性。
// 计算属性
// 类,结构体和枚举类型中可以定义计算属性,
// 计算属性会提供一个getter和一个可选的setter来间接获取和设置其他属性和值。
// 计算属性的声明只能使用var关键字
var frame = rect(origin: Point(x: 2, y: 2), size: Size.init(width: 10, height: 10));
//!< 不能使用`let`..
frame.center = Point.init(x: 10, y: 10);
//!<不重新赋值便会得到Point(x: 7, y: 7)
print("应该调用了set方法后:\(frame.center)");
//Point(x: 10, y: 10)
// 只读计算属性
// 具有getter但没有setter方法的计算属性。只读计算属性始终返回一个值,
// 可以通过点语法访问,但不能设置为其他值。
// 属性观察者
// 我们可以为我们定义的任何存储属性添加属性观察者,除了懒储存属性,
// 即使用lazy修饰的变量属性。也可以通过在子类中重写继承自父类的属性
// (存储属性和计算属性均可),为该属性添加属性观察者。
// willSet存储新值之前调用,会将新属性值作为常量参数传递,newValue
// didSet存储新值之后调用,会将旧属性值作为常量参数传递,oldValue
// 可以在属性中定义willSet和didSet中的任一个,或者两者都定义。
//使用
//属性观察者
let propertyObj = propertyObeserver.init();
propertyObj.progress = 200;
//!< 将要设置的新值200; 设置的新值与旧值得差值200
propertyObj.progress = 100;
//!< 将要设置的新值将要设置的新值100; 设置的新值与旧值得差值-100
/**
注意:如果将具有观察者的属性作为输入输出参数传递给函数,
则始终调用willSet和didSet观察者方法。因为in-out参数的copy-in copy-out内存模型:在函数结束的时候作为参数的属性的值总是会重新写入原始的属性中。
关于in-out参数传递时的copy-in copy-out:
copy-in copy-out的行为也称为按值调用结果,具体的行为有:
•调用该函数时,将复制inout参数的值。
•在函数体中,参数值的副本被修改
•当函数返回的时候,参数值的副本将会赋值给原始的参数。
例如:计算属性或者具有观察者的属性作为函数的输入输出参数传递时,
它们的getter方法会作为函数调用的一部分被调用。
它们的setter作为函数返回的一部分被调用。
作为优化,当参数值是存储在内存中的物理地址时,在函数的内部和外部会使用相同的
内存区域。这个优化被称为引用调用。它满足了copy-in copy-out模型的所有要求,
同时消除了复制的开销。使用copy-in copy-out模型编写代码,而不依赖于按引用调用优化,
以便在有或没有优化的情况下copy-in copy-out的行为是正确的。
在函数内,不要访问作为输入输出参数传递的值,即使原始值在当前范围内可用。
因为违反了Swift的内存独占性,同时也无法将相同的值传递给多个输入输出参数。
*/
// increment(&stepSize);
//!< Error: 访问 stepSize冲突了
// 一个捕获输入输出参数的闭包或者嵌套函数一定是非逃逸的。
// 如果需要捕获输入输出参数而不改变它或者要观察其他代码所做的更改,
// 需要使用捕获列表以不可变的方式显式捕获参数。
//方法的调用
var bb1 = 7;
let cc1 = ViewController.someFunction1(a: &bb1)();
print("\(bb1)...\(cc1)");
//7...8
//调用
var bb2 = 7;
ViewController.mutateFuncation(x: &bb2);
print("可变的调用结果\(bb2)");
//!< 可变的调用结果10
// 全局和局部变量
// 全局变量:是在任何函数,方法,闭包或类型的上下文之外定义的变量。
// 局部变量:是在函数,方法或闭包上下文中定义的变量。
/**
类型属性
实例属性:特定类型的实例的属性。每次创建的特定类型的新实例,
它都会有属于自己的一组属性值,并且和其他的实例是区分开的。
类型属性:属于该类型本身的属性,不管我们创建多少该类型的实例,类型属性只会有一个副本。
类型属性可以定义对特定类型的所有实例通用的值。
例如所有实例都可以使用的常量属性(如C中的静态常量),
或者所有实例都可以使用的存储全局值的变量属性(如C中的静态变量)。
存储的类型属性可以是变量或常量。计算类型属性始终声明为变量属性,
与实例计算属性的方式相同。
类型属性语法
C和Objective-C中,类型属性是将与类型关联的静态常量和变量定义为全局静态变量。
参考
Swift中,类型属性是作为类型定义的一部分进行定义的,在类型的外部{}中,
并且每个类型属性都显式限定为它支持的类型。
使用static关键字定义类型属性。对于类类型的计算类型属性,
可以使用class关键字来代替static定义类型属性,从而允许子类重写父类的实现。
*/
// 查询和设置类型属性
// 使用点语法进行查询类型属性和设置类型属性,就像实例属性一样。
// 但是类型属性是在类型上查询和设置类型属性,而不是在该类型的实例上
print("获取结构体的存储类型属性\(SomeStructure.storedTypeProperty)")//!< 获取结构体的存储类型属性Some value.
SomeStructure.storedTypeProperty = "Another value."
print("设置结构体的存储类型属性后\(SomeStructure.storedTypeProperty)")//!< 设置结构体的存储类型属性后Another value.
print("获取结构体的计算类型属性\(SomeStructure.computedTypeProperty)")//!< 获取结构体的计算类型属性1
print("获取枚举类型的计算类型属性\(SomeEnumeration.computedTypeProperty)")//!< 获取枚举类型的计算类型属性6
print("获取类类型的计算类型属性\(SomeClass.computedTypeProperty)")//!< 获取类类型的计算类型属性27
print("获取子类的类类型的计算类型属性\(subSomeClass.overrideableComputedTypeProperty)")//!< 获取类类型的计算类型属性227
struct Resolution {
var width = 0
var height = 0
}
class VideoMode {
var resolution = Resolution()
var interlaced = false
var frameRate = 0.0
var name: String?
}
//定义一个结构体
struct StructEnumType {
//! 定义一个常量存储属性
let constantPro : Int
//! 定义一个变量存储属性
var varPro : Int //!< `var`关键字可以这般声明属性,但是必须在初始化方法中赋值。
}
//! 定义一个坐标点的结构体
struct Point {
var x = 0,y = 0
}
//! 定义一个大小的结构体
struct Size {
var width = 0,height = 0
}
/* 定义一个rect的结构体:一个rect会有原点,会有大小 根据这两个存储属性,可以计算得出 rect的center。
因此我们会在`rect`中定义一个计算属性。利用其提供的`getter`和`setter`方法进行值得获取,和值被设置时进行相应处理*/
struct rect {
var origin = Point()
var size = Size()
//! get 和 set 都需要出现,
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 {
//`newValue`便是所赋新值的点,系统的默认值
origin.x = newValue.x - (size.width / 2)
origin.y = newValue.y - (size.height / 2)
}
// set(customValue){
// //`customValue`便是所赋新值的点
// origin.x = customValue.x - (size.width / 2)
// origin.y = customValue.y - (size.height / 2)
// }
}
}
//! 定义面积的结构体
struct areaStruct {
var width = 0.0,height = 0.0
// var area:Double {
// get {
// return width * height
// }
// }
var area:Double {
return width * height
}
}
//属性观察者
class propertyObeserver: NSObject {
var progress = 0 {
willSet(newprogress) {
print("将要设置的新值\(newprogress)")
}
// willSet {
// print("将要设置的新值\(newValue)")
// }
didSet(oldProgress) {
print("设置的新值与旧值得差值\(progress - oldProgress)")
}
// didSet {
// print("设置的新值与旧值得差值\(progress - oldValue)")
// }
}
}
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
}
}
class subSomeClass: SomeClass {
//! 当父类实用static时 此处的重写会报错`Cannot override static property1
override class var overrideableComputedTypeProperty: Int {
return 227
}
}
//实用场景
struct volume {//!< 定义音量结构体
static let maxLevel = 20 //!< 最大的音量
static var isNorse : Bool = false //!< 是否是噪音
var currentLevel: Int = 0 {//!< 当前音量
didSet {
if currentLevel > volume.maxLevel {
currentLevel = volume.maxLevel
}
if currentLevel > volume.maxLevel/2 {
volume.isNorse = true
} else {
volume.isNorse = false
}
}
}
}
var stepSize = 1;
func increment(_ number: inout Int) {
number += stepSize;
}
static func someFunction1(a: inout Int) -> () -> Int {
return { [a] in return a + 1 }
}
//可变的输入输出参数
static func mutateFuncation(x:inout Int) ->Void{
//输出输出参数`x`会被改变,所以定义一个本地的副本
var localX = x
//在函数结束之前需要调用defer关键字修饰的代码,一遍将副本的改变操作,赋值给原始参数`x`
defer {/*< 在结束范围之前的'defer'语句总是立即执行。
作用:修饰一段函数内任一段代码,使其必须在函数中的其余代码都执行完毕,函数即将结束前调用*/
x = localX
}
changeValue(b: &localX)
}
static func changeValue(b : inout Int) {
b += 3
}
网友评论