iOS原理之Category的关联对象
2019-05-18 本文已影响0人
yqc5521
import UIKit
//类似于hash表
class CustomMutableDictionary: NSObject {
var dict:NSMutableDictionary?
override init() {
super.init()
dict = NSMutableDictionary()
}
func setObject(_ anObject: Any?, forKey aKey: NSCopying) {
dict?.setValue(anObject, forKey: aKey as! String)
}
func object(forKey aKey: Any) -> Any? {
return dict?.value(forKey: aKey as! String)
}
}
//
// ObjcReference.swift
// iOS底层
//
// Created by yanqunchao on 2019/5/18.
// Copyright © 2019 yanqunchao. All rights reserved.
//
import UIKit
enum AccociationPolicy:Int {
case OBJC_ASSOCIATION_ASSIGN = 0
case OBJC_ASSOCIATION_RETAIN_NONATOMIC = 1
case OBJC_ASSOCIATION_COPY_NONATOMIC = 2
}
class ObjcReference: NSObject {
//对象关联者
class ObjcAssociation: NSObject {
var value:Any? //关联的值
var policy: AccociationPolicy? //关联的策略
}
//关联对象表
class ObjectAssociationMap: CustomMutableDictionary {
// key refs:Int? //对象关联属性的标记
// value objectAsscociate: ObjcAssociation? //与属性标记对应的关联者
}
//关联者哈希表
class AssociationsHashMap: CustomMutableDictionary {
// key disguised_ptr_t:Int? //存放关联对象的地址
// value objectAsscociateMap: ObjectAssociationMap? //与对象地址对应的关联对象表
}
/**
* 全局关联对象管理者
*/
class AssociationsManager: NSObject {
static let map: AssociationsHashMap = AssociationsHashMap()
}
//为某个对象的某个属性关联值
static func objectSetAssociativeReference(object: AnyObject, key: String, value: Any?, policy: AccociationPolicy) {
let map = AssociationsManager.map
let keyAddr = Unmanaged.passUnretained(object as AnyObject).toOpaque()
let keyAddrStr = "\(keyAddr)"
//先找object对应的map
var objectAsscociationMap = map.object(forKey: keyAddrStr) as? ObjectAssociationMap
if objectAsscociationMap == nil { //如果没有找到,创建一个map
objectAsscociationMap = ObjectAssociationMap()
}
if value == nil { //设置的值为空
objectAsscociationMap!.setObject(nil, forKey: key as NSCopying)
}else{
let objcAssociation = ObjcAssociation()
objcAssociation.value = value
objcAssociation.policy = policy
objectAsscociationMap!.setObject(objcAssociation, forKey: key as NSCopying)
}
map.setObject(objectAsscociationMap, forKey: keyAddrStr as NSCopying)
}
//获取某个对象的某个属性
static func objectGetAssociativeReference(object: AnyObject, key: String) -> Any?{
let map = AssociationsManager.map
let keyAddr = Unmanaged.passUnretained(object as AnyObject).toOpaque()
let keyAddrStr = "\(keyAddr)"
guard let objectAsscociationMap = map.object(forKey: keyAddrStr) as? ObjectAssociationMap else {
return nil
}
guard let objcAssociation = objectAsscociationMap.object(forKey: key) as? ObjcAssociation
else {
return nil
}
return objcAssociation.value
}
//移除某个对象的所有关联属性
static func objectRemoveAssocations(object: AnyObject) {
let map = AssociationsManager.map
let keyAddr = Unmanaged.passUnretained(object as AnyObject).toOpaque()
let keyAddrStr = "\(keyAddr)"
guard (map.object(forKey: keyAddrStr) as? ObjectAssociationMap) != nil else {
return
}
map.setObject(nil, forKey: keyAddrStr as NSCopying)
}
}
//
// CategoryBasementAssociateObjectViewController.swift
// iOS底层
//
// Created by yanqunchao on 2019/5/18.
// Copyright © 2019 yanqunchao. All rights reserved.
//
import UIKit
///关联对象
class CategoryBasementAssociateObjectViewController: UIViewController {
class Category1: NSObject {
var name:String? {
get{
return (ObjcReference.objectGetAssociativeReference(object: self, key: "name") as? String) ?? ""
}
set{
ObjcReference.objectSetAssociativeReference(object: self, key: "name", value: newValue, policy: AccociationPolicy.OBJC_ASSOCIATION_COPY_NONATOMIC)
}
}
var number:String? {
get{
return (ObjcReference.objectGetAssociativeReference(object: self, key: "number") as? String) ?? ""
}
set{
ObjcReference.objectSetAssociativeReference(object: self, key: "number", value: newValue, policy: AccociationPolicy.OBJC_ASSOCIATION_COPY_NONATOMIC)
}
}
}
override func viewDidLoad() {
super.viewDidLoad()
self.view.backgroundColor = .white
let category1 = Category1()
category1.name = "小明"
category1.number = "12345"
let category2 = Category1()
category2.name = "小明2"
category2.number = "67890"
print(category1.name ?? "")
print(category1.number ?? "")
print(category2.name ?? "")
print(category2.number ?? "")
category1.name = nil
print(category1.name ?? "")
//调用结束时,清除关联对象
ObjcReference.objectRemoveAssocations(object: category1)
ObjcReference.objectRemoveAssocations(object: category2)
}
}