类的定义

所有的属性和方法都是全局共享的,不需要 import

import UIKit
// 定义 Person 类,继承自 NSObject
class Person: NSObject {

  // 对象属性应该可变的,可选项允许变量为空
  var name: String

}

构造函数

给属性分配空间,设置初始值,父类提供了构造函数需要对父类的构造函数进行扩展,使用关键字override

import UIKit
class Person: NSObject {

  var name: String

  override init() {
    // name初始化只能在 super.init() 上面
    name = "Zhang San"
    super.init()
    // name = "Zhang San" 再此处写会报错
  }
}
// 实例化
let p = Person()
print(p.name); // Zhang San

函数重载

函数名相同,参数个数和类型不同

class Person: NSObject {
  var name: String
  var age: Int
  // 如果重载构造函数,系统默认构造函数就不能再被访问
  init(name: String, age: Int) {
    self.name = name
    self.age = age
  }
}

KVC

Key-value coding,通过Key名直接访问对象属性或赋值,而不需要调用明确的存取方法

class Person: NSObject {
  var name: String?
  // 设置 age 的初始值,因为Int是基本类型,不存在 nil 的概念,所以不能写成 var age: Int?
  var age: Int = 0

  init(dict: [String: Any]) {
    super.init()
    setValuesForKeysWithDictionary(dict)
  }
}
// 实例化并传入参数 dict
let p = Person(["name": "Zhang San", "age": 20])

便利构造函数

能够提供条件检测,允许返回nil,默认的构造函数必须要创建对象,便利构造函数必须以self.的方式调用其他构造函数创建对象

class Person: NSObject {
  var name: String?
  var age: Int = 0

  init(dict: [String: Any]) {
    super.init()
    setValuesForKeysWithDictionary(dict)
  }

  convenience init?(name: String, age: Int) {
    if age < 0 || age > 100 {
      return nil
    }
    // 调用其他构造函数初始化属性
    self.init(dict: ["name": name, "age": age])
  }
}
let p = Person("name": "Zhang San", age: 101)
// 一般解包时需要用 ! ,但此时会报错
print("name: \(p!.name), age: \(p!.age)")
// 需要用 ? 来解包,表示如果p为nil,就不会继续调用后续的属性或方法
print("name: \(p?.name), age: \(p?.age)"); // name: nil, age: nil

对象释放方法,与dealloc类似,主要负责对象被销毁前的内存释放工作,不允许重载,不允许带参数,不允许直接调用,会先调用子类的释放函数再调用父类的

需要程序员销毁的内容

  • 通知 (不注销不会崩溃)
  • KVO (不注销会崩溃)
  • NSTimer (会对target (self) 进行强引用)
class Person: NSObject {
  deinit {
    print("Person deinit")
  }
}

懒加载

本质上是一个闭包,第一次访问属性时会执行后面的闭包,将返回值保存在属性中,下次访问就不会执行闭包,直接获取属性的值

如果没有lazy,会在initWithCoder方法中被调用,当二进制的storyboard被还原成视图控制器对象后,就会被调用

import UIKit
class ViewController: UIViewController {
  // 懒加载 Person 类
  lazy var person: Person = {
    print("懒加载")
    return Person()
  }()

  // 还可以写成以下格式
  let personFunc = { () -> Person in
    print("懒加载")
    return Person()
  }
  lazy var demoPerson: Person = self.personFunc()

  // 懒加载的简单写法
  lazy var demoPerson: Person = Person()

  // 闭包中的 self. 是不能省略的
  var name: String? = "Zhang San"
  lazy var title: String? = {
    return "Mr " + (self.name ?? "")
  }
  // 输出 Mr Zhang San
}

getter和setter

在Swift中极少用,仅供参考 OC中使用getter进行懒加载,而Swift提供了lazy关键字

class Person: NSObject {
  private var _name: String
  var name: String? {
    get {
      // 返回 _成员变量的值
      return _name
    }
    get {
      // 使用 _成员变量记录新的值
      _name = newValue
    }
  }
}
// 使用
let p = Person()
p.name = "Zhang San"
print(p.name); // Zhang San

read only

只读属性,也叫,每次调用时都会执行大括号中的代码

只写getter方法

print var _name: String?
var name: String? {
  get {
    return _name
  }
}
// 只读属性可以简写,省略 get{}
var name: String? {
  return _name
}

懒加载与计算型属性的区别

懒加载

  • 只计算一次
  • 需要开辟单独的空间保存计算结果
  • 闭包的代码再也不会被调用
  • 如果计算量很大,需要提前准备

计算型属性

  • 每次都要计算,浪费性能
  • 不需要开辟额外的空间

类函数(静态函数)

import UIKit
class Person: NSObject {
  // 定义静态成员属性
  static var text: String = "Test"
  // 定义类函数(静态函数)
  class func staticFunc() {
    print("类函数")
  }
}
// 调用

单例

import UIKit
class Person: NSObject {
  // 定义静态成员属性
  static var instance: Person?
  // 定义标识,只让diepatch_once中的代码运行一次
  static var onceToken: dispatch_once_t = 0
  // 提供全局访问类
  class func person() -> Person {
    dispatch_once(&onceToken) { () -> Void in
      // 实例化类
      instance = Person()
    }
    // 强制解包并返回
    return instance!
  }
  // 单例的懒加载写法
  static let person2: Person = {
    return Person()
  }()
}

extension

对在已存在的类、类型进行扩展,但不能覆盖现有功能

计算属性

extension Double {
  var km: Double { return self * 1000.0 }
  var m: Double { return self }
  var cm: Double { return self / 100.0 }
  var mm: Double { return self / 1000.0 }
  // 英尺
  var ft: Double { return self / 3.28084 }
}
// 使用
let threeFeet = 3.ft
print("3英尺是 \(threeFeet)"); // 3英尺是 0.914399970739201 米

扩展方法

以下例子是对Int使用,也可以对自定义的类使用

extension Int {
  func repetitions(task: () -> Void) {
    for _ in 0..<self {
      task()
    }
  }
}
// 使用(尾随闭包的形式)
3.repetitions {
  print("Hello"); // Hello Hello Hello
}
// 使用(普通传参)
3.repetitions(task: {
    print("Hello"); // Hello Hello Hello
})

视图模型

模型通常继承自NSObject,可以使用KVC设置属性,简化对象构造 而视图模型没有父类,所有内容都要从头构造

视图模型是封装业务逻辑,通常没有复杂的属性

import Foundation
class UserAccountViewModel {
  // 用户模型
  var account: UserAccount?
  // 构造函数
  init() {

  }
}

协议

类似接口,用于制定属性和方法,让其他遵守协议的地方实现

import UIKit
protocol Pet {
  // 协议属性,如果只有 get 则是只读属性
  var name: String { get set }
  // 协议方法
  func playWith()
  func fed()
}
class Animal {
  var type: String = "mammal"
}
// 继承父类同时实现协议,需要先写父类,再写协议
class Dog: Animal, Pet {
  var name: String = "Puppy"
  func playWith() {
    print("wong")
  }
  func fed() {
    print("I love Bones")
  }
}

属性观察者

在属性即将赋值、赋值后进行操作,默认赋值和init初始化方法中的赋值不会触发属性观察者

import UIKit
class person {
  var age = 0 {
    // 即将赋值时
    willSet(newAge) {
      print("原值:\(age),即将被赋值为:\(newAge)")
    }
    // 赋值后
    didSet(oldAge) {
      print("原值:\(oldAge),即将被赋值为:\(age)")
    }
  }
}
评论区域将在可见后加载…