- 存储属性
- 计算属性
- 属性观察器
- 类型属性
-
存储属性
存储常量或变量作为实例的一部分,用于类和结构体。
- 常量存储属性:let name = value
- 变量存储属性:var name = value
- 延迟存储属性(类似OC懒加载) : lazy var = value
栗子
等下!😲 先谈谈Swift中的 问号"?" , "!"感叹号
问号?
a.声明时添加?,告诉编译器这个是Optional的,如果声明时没有手动初始化,就自动初始化为nil
b.在对变量值操作前添加?,判断如果变量时nil,则不响应后面的方法。
叹号!
a.声明时添加!,告诉编译器这个是Optional的,并且之后对该变量操作的时候,都隐式的在操作前添加!
b.在对变量操作前添加!,表示默认为非nil,直接解包进行处理
所以
可以理解为: '!'修饰的变量不可为nil, '?'修饰的变量可为nil. 所以在访问'!'修饰的变量一旦不小心为nil,则Crash
// MARK: Property
let name1: String = "String" // 可设置属性类型
let name2 = "sd" // 可不设置属性类型
var namevar1: String? // 可不设初始值
var namevar2: String = "namevar2" //可设置初始值
var mainView = UIView() // 初始值为一个UIView对象
lazy var label: UILabel = {
let tempLabel = UILabel()
// Config
return tempLabel
}() // lazy 创建一个label
// MARK: func
override func viewDidLoad() {
super.viewDidLoad()
print("name1=",name1)
print("name2=",name2)
print("namevar1=",namevar1) // 若访问为空的属性,会报警告提示 "namevar1 ?? <#default value#>"
print("namevar2=",namevar2)
print("mainView=",mainView)
print("label=",label)
/*
打印结果:
name1= String
name2= sd
namevar1= nil
namevar2= namevar2
mainView= <UIView: 0x7fa2dad09ea0; frame = (0 0; 0 0); layer = <CALayer: 0x600000034200>>
label= <UILabel: 0x7fa2dad063a0; frame = (0 0; 0 0); userInteractionEnabled = NO; layer = <_UILabelLayer: 0x608000092890>>
*/
}
注意:
必须将延迟存储属性声明成变量(使用 var 关键字),因为属性的初始值可能在实例构造完成之后才会得到。而常量属性在构造过程完成之前必须要有初始值,因此无法声明成延迟属性。
-
计算属性
类似OC重写Setter Getter 。
**类 ** 结构体 枚举 可定义计算属性。
通常通过计算属性间接获取或设置其他属性 或 变量值。
栗子
还是拿官方栗子吧(设置Center
可以改变point
, 当然设置point
size
可获取center
)
“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))")
// 打印 "square.origin is now at (10.0, 10.0)”
只读计算属性: ( 只有 getter
没有 setter
声明可以去掉 getter
关键字和花括号)
private var width: NSInteger?
private var height: NSInteger?
var perimeter: NSInteger {
return width! + height!
}
override func viewDidLoad() {
super.viewDidLoad()
width = 10
height = 10
print(perimeter) //输出: 20
}
注意:
计算属性只能使用关键字 var 定义,为毛?因为它是变的。
-
属性观察器
检测属性的变化
每次属性被赋值的时候调用
延迟属性(lazy), 计算属性不可直接使用
栗子
/*
// 不赋初始值
var stringData: String?{
willSet{
}
didSet{
}
}
*/
//赋初始值 演示:
var stringData: String = "First"{
willSet{
print("stringData=",stringData,"newValue=",newValue)
}
didSet{
print("stringData=",stringData,"oldValue=",oldValue)
}
}
override func viewDidLoad() {
super.viewDidLoad()
stringData = "hello,world"
/*
输出:
stringData= First newValue= hello,world
stringData= hello,world oldValue= First
*/
}
`willSet` 在新的值被设置之前调用(观察器会将新的属性值作为常量参数传入”默认名称`newValue`)
`didSet` 在新的值被设置之后立即调用(观察器会将旧的属性值作为参数传入,可以为该参数命名或者使用默认参数名 `oldValue`。如果在 didSet 方法中再次对该属性赋值,那么新值会覆盖旧的值。)
任意选哪个都可,也可全选,视编码时具体情况而定
-
类型属性
跟实例的存储型属性不同,必须给存储型类型属性指定默认值
使用关键字 static 来定义,通过类型本身来访问
它们只有在第一次被访问的时候才会被初始化。即使它们被多个线程同时访问,系统也保证只会对其进行一次初始化,并且不需要对其使用 lazy
修饰符。
栗子
下面栗子演示了“存储型和计算型类型属性的语法:
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 来支持子类对父类的实现进行重写
*/
}
官方的一个很好的栗子,如果你看懂了这个🌰.恭喜你兄弟💐。你已经掌握了Swift的属性篇.
struct AudioChannel {
static let thresholdLevel = 10 //“音量的最大上限阈值”常量存储型类型属性
static var maxInputLevelForAllChannels = 0 //“最大音量”变量存储型类型属性
var currentLevel: Int = 0 {
didSet {
if currentLevel > AudioChannel.thresholdLevel {
// 将当前音量限制在阀值之内(可在这儿直接赋值,放心这不会造成属性观察器被再次调用)
currentLevel = AudioChannel.thresholdLevel
}
if currentLevel > AudioChannel.maxInputLevelForAllChannels {
// 存储当前音量作为新的最大输入音量
AudioChannel.maxInputLevelForAllChannels = currentLevel
}
}
}
}
总结:
虽然平时开发中,已经编入Swift了。但想好好研究巩固Swift,所以今天结合了下官方文档写了这篇文章。写完之后感觉爽爽哒。嘿嘿嘿Swift属性篇完成了,兄弟们如果喜欢的话,敬请期待我的Swift下一篇文章.别忘点赞啊,给哥们动力。感谢!
你坚持过很认真的做一件事儿吗?为何不试试......
网友评论