协议
只能被class继承的协议
protocol Runnable1: AnyObject{}
protocol Runnable2: class{}
@objc protocol Runnable3 {}
- 被
@objc
修饰的协议,还可以暴露给OC去遵守实现 - 可以通过
@objc
定义可选协议,这种协议只能被class遵守
@objc protocol Runnable{
func run1()
@objc optional func run2()
func run3()
}
class Dog: Runnable {
func run1() { print("Dog run1")}
func run3() {print("Dog runn3")}
}
var d = Dog()
d.run1()
d.run3()
dynamic
- 被
@objc dynamic
修饰的内容会具有动态性,比如调用方法会走runtime那一套流程
class Dog: NSObject {
@objc dynamic func test1() {}//走runtime机制
func test2() {}//走虚表一套流程
}
var d = Dog()
d.test1()
d.test2()
KVC/KVO
- Swift支持KVC/KVO的条件
- 属性所在的类、监听器最终继承自NSObject
(KVC/KVO也是依赖于runtime的)
- 用@objc dynamic
修饰对应的属性
block方式的KVO
class Person: NSObject {
@objc dynamic var age:Int = 0
var observation:NSKeyValueObservation?
override init() {
super.init()
observation = observe(\Person.age, options: .new, changeHandler: { person, change, in
print(change.newValues as Any)
})
}
}
关联对象
- 在Swift中,class依然可以使用关联对象
- 默认情况,
extension
不可以增加存储属性,可以增加计算属性,因为计算属性本质是方法,不占用内存
protocol Runnable {
}
extension Runnable{
}
class Person:Runnable {
var age = 0
}
extension Person{
var weight = 0//报错:Extensions must not contain stored properties
}
- 借助关联对象,可以实现类似`extension`为`class`增加存储属性的效果
extension Person{
private static var AGE_KEY : Void?//这里用Void?或者bool类型,目的是为了省内存,Void?或者bool类型都只占用一个字节
//类型存储属性,本质是全局变量
var age:Int{
get{
objc_getAssociatedObject(self, &Person.AGE_KEY) as! Int
}
set {
objc_setAssociatedObject(self, &Person.AGE_KEY, newValue, .OBJC_ASSOCIATION_ASSIGN)
}
}
}
var p = Person()
p.age = 10
print(p.age)
资源名管理
- 这种做法实际上是参考了Android的资源名管理方式
enum R{
enum string:String {
case add = "添加"
}
enum image:String {
case logo
}
enum segue:String {
case login_main
}
}
let img = UIImage(named: R.image.logo.rawValue)
let btn = UIButton(type: .custom)
btn.setTitle(R.string.add.rawValue, for: .normal)
performSegue(withIdentifier: R.segue.login_main.rawValue, sender: self)
资源名管理的其他思路
enum R{
enum image {
static var logo = UIImage(named: "logo")
}
enum font {
static func arial(_ size:CGFloat) -> UIFont?{
UIFont(name: "Arial", size: size)
}
}
}
let img = R.image.logo
let font = R.font.arial(14)
多线程开发 - 异步
//gcd
DispatchQueue.main.async {
//拿到主线程
}
DispatchQueue.global().async {
//拿到全局并发队列
print(Thread.current)//打印当前线程
DispatchQueue.main.async {
//回到主线程
}
}
或者:
let item = DispatchWorkItem{
//子线程
print("1",Thread.current)
}
DispatchQueue.global().async(execute: item)
item.notify(queue: DispatchQueue.main){
//主线程
}
多线程开发 - 延迟
let time = DispatchTime.now()+3
DispatchQueue.main.asyncAfter(deadline: time){
print("1")
}
多线程开发 - once
-
dispatch_once
在Swift中已被废弃,取而代之
- 可以用类型属性或者全局变量/常量:静态的存储属性(static
),也就是类型存储属性,他在程序运行过程中,只初始化一次,因为本质就是全局变量,全局变量在运动过程中只初始化一次,而且static
修饰的属性默认是lazy
的,所以只想走一次代码的可以用下面的方法
- 默认自带lazy
+dispatch_once
效果
static var age:Int = getAge()
static func getAge() -> Int{
print("getAge")
return 0
}
print(Self.age)
print(Self.age)
print(Self.age)
//这种办法声明的getAge只会调用一次,即使是所在的ViewController被销毁之后重新创建,age也不会再走一遍初始化getAge的方法
fileprivate var initTask:Void = {
print("init -------")
}()
let _ = initTask
let _ = initTask
//只走一次print("init -------")代码
多线程开发 - 加锁
import Foundation
public struct Cache{
private static var data = [String:Any]()
private static var lock = DispatchSemaphore(value: 1)//value值是几,就表示允许几条线程同时修改
public static func get(_ key:String) -> Any?{
data[key]
}
public static func set(_ key:String,_ value:Any){
lock.wait()
defer{lock.signal()}
data[key] = value
}
}
或者:
import Foundation
public struct Cache{
private static var data = [String:Any]()
private static var lock = NSLock()
public static func get(_ key:String) -> Any?{
data[key]
}
public static func set(_ key:String,_ value:Any){
lock.lock()
defer {lock.unlock()}
data[key] = value
}
}
函数中有递归容易造成死锁,用递归锁解决
import Foundation
public struct Cache{
private static var data = [String:Any]()
private static var lock = NSRecursiveLock()
public static func get(_ key:String) -> Any?{
data[key]
}
public static func set(_ key:String,_ value:Any){
lock.lock()
defer {lock.unlock()}
data[key] = value
}
}