struct Car {
init() { print("Car int") }
func run() { print("Car run") }
}
struct Circle {
// 1.存储属性
// 存储属性占用对象内存空间,用来存储对象的某个特定值
var radius: Double
// 2.延迟存储属性
// 当某个属性希望在使用到的时候再创建时,可以使用 lazy 修饰
// lazy表示延迟加载,即使用到的时候在加载
// 如下列属性car,有可能在使用Circle对象的过程中,一直用不到car对象
// 如果不延迟,Circle对象一创建car对象也创建,造成内存空间浪费
//
// 注意1:lazy只能使用var声明,因为let要求在变量初始化完成之前就拥有值
// 注意2:lazy不能保证线程安全,多小线程访问的时候可能导致创建多个对象
lazy var car = Car()
// 若要线程安全,可这样考虑
lazy var car1: Car = {
Car()
/** 在这里来做线程安全的事(伪代码)
dispatch_once {
Car()
}
*/
}()
// 注意3,当结构体包含延迟存储属性的时候,只有var对象才能访问延迟存储属性
// 因为延迟存储属性初始化时需要改变结构体内存,而结构体的创建的实例
// 如果使用let初始化,则表明内存不能再被更改,因此结构体包含延迟存储
// 属性的时候,职能用var修饰结构创建出来的对象
// 若是类则没有这个限制,因为let只修饰p变量,不修饰堆空间p对象内存
/**
struct Point {
var x = 0
var y = 0
lazy var z = 0
}
let p = Point()
p.z // 这句代码会初始化z改变结构体内存,和let冲突
// 应该这样创建对象
var p = Point()
p.z
*/
// 3.计算属性
// 计算属性不占用内存空间,它类只有中Setter和Getter方法
// 本质上该属性就是一对Setter和Getter方法而已
// 如果要让计算属性只读,只提供getter(get)方法即可
//
// 注意:如果提供了set,则必须有get,即不能只提供写而不提供读
// 计算属性职能用var定义,计算属性的值可能发生改变,即使是只读的也可能发生改变
//
// set方法中会默认提供newValue形参,如要该表只需要明确声明形参 set(theValue)
// get方法中会默认提供newValue形参,如要该表只需要明确声明形参 set(theValue)
var diameter: Double {
set {
radius = newValue / 2
}
get {
return radius * 2
}
}
// 枚举中rawValue就是计算属性实现
enum TestEnum: Int {
case test1 = 1, test2, test3
var rawValue: Int {
// 只有get方法,省略get
switch self {
case .test1: return 1
case .test2: return 2
case .test3: return 3
}
}
}
// 4.属性观察期(类似OC的KVO)
// 这个属性咋一看很想计算属性
// 同样 willSet 和 didSet自带默认参数newValue 和 oldValue
// newValue是新设置的值,oldValue是以前的值
//
// 注意1:在初始化器(init)中设置属性值,不会引起willSet、didSet调用
// 原因很简单:在初始化器中监听属性值变化没有意义,监听的目的是为了
// 拦截或做并做某些改变,初始化的时候我们本是就可以控制该行为
// 注意2:在定义的时候设置初始值也不会触发willSet、didSet,和注意1很像
// 在这个位置监听拦截也没有意义,因为这里行为也是我们控制的
// 注意3:属性监听器(willSet、didSet)和计算属性(get、set)不能共存
// 即存储在get或set、就不能存在willSet或didSet,这两对方法相互
// 排斥,其实原因也容易理解,既然我们都可以控制set和get了
// 那么willSet、didSet将变得毫无意义
//
// 注意4:属性监听器更准确的说法(我认为)叫监听器,因为它不仅可以监听
// 成员属性变化,还可以监听全局变量、局部变量等的变化
/**
// 全局变量
var num: Int {
get { 10 }
set { if newValue < 0 // code... }
}
// 局部变量
func test() {
var num: Int {
get { 10 }
set { if newValue < 0 // code... }
}
}
*/
var perimeter: Double = 10 {
willSet {
print("perimeter:\(newValue)")
}
didSet {
print("perimeter:\(oldValue)")
}
}
// 5.类型属性(Type Property 类属性)
// 实例属性,每个实例都拥有一份该属性
// 类属性,每个类拥有一份,该类的素所有实例共用一份
// 存储类属性,本质上是全局变量,只是访问权限被限定到该类
// 实际上类属性就是全局变量,而起访问权限的限制事实上是编译器的语法糖而已
//
// 修饰符用 结构体:static 类:static、class
// static修饰的子类不能再重写(结构体不支持继承)
// class修饰的子类可以重写
// 不同于存储实例属性,类属性要求必须更定初始值,因为init并不会初始化类属性
/**
class let prperty1 = 0
static var prperty2 = 0
*/
//
// 注意1,类存储属性默认已经是lazy,并且线程安全(底层用dispatch_once实现)
// 这样可以保证只初始化一次
// 注意2,类存储类型属性,可以使let,因为类属性的本质是全局变量,和当前类或者
// 实例变量的内存结构没关系,即使延迟初始化也不会对当前实例造成影响,只是
// 只不过let让其只能初始化一次而已
static let property1 = 0
static var property2 = 0
// 6.计算类型类属性
static var property3: Int {
set { property2 = newValue }
get { return property2 }
}
init(radius: Double) {
self.radius = radius
}
}
let c = Circle(radius: 1)
print(c.radius)
print(c.diameter)
// 6.一个简单的单例设计
class FileManager {
// 第一种
public static let shared = FileManager()
// 第二种
public static let shared1 = { () -> FileManager in
let instance = FileManager()
// your code ...
// 由于static特性,这里实际上已经是线程安全
return instance;
}()
private init(){}
}
// 7.枚举可以定义 static类属性(不能定义实例属性)
enum TestEnum: String {
static var property1 = 0
static var property2: Int {
set { property1 = newValue }
get { return property1 }
}
case A,B,C,D
}
网友评论