iOS原理之Runtime-__weak的实现原理

//
//  RuntimeBasement__weekViewController.swift
//  iOS底层
//
//  Created by yanqunchao on 2019/5/21.
//  Copyright © 2019 yanqunchao. All rights reserved.
//

import UIKit

let WEAK_INLINE_COUNT = 4

class RuntimeBasement__weekViewController: UIViewController {
  
    class WeakEntryT:NSObject {
        var referent:NSObject? // 被弱引用的对象
        
        var inline_referrers: [UnsafeMutablePointer<NSObject>?] = [UnsafeMutablePointer<NSObject>?](repeating: nil, count: WEAK_INLINE_COUNT)
        init(newReferent:NSObject,newReferrer:UnsafeMutablePointer<NSObject>) {
            print("【创建】新的弱引用入口")
            self.referent = newReferent
            inline_referrers[0] = newReferrer
            inline_referrers[0]?.pointee = newReferent
            for i in 1..<WEAK_INLINE_COUNT{
                inline_referrers[i] = nil;
            }
        }
    }
    class RefcountMap:NSObject {
        
    }
    
    class WeakTableT:NSObject {
        var weakEntries:[WeakEntryT?] = [WeakEntryT?](repeating: nil, count: 4)
        var mask:Int?
    }
    
    class SideTable {
        var recnts:RefcountMap?
        var weak_table: WeakTableT?
        
        init() {
            self.weak_table = WeakTableT()
        }
        class func lockTwo(oldTable:SideTable,newTable:SideTable){}
        class func unlockTwo(oldTable:SideTable,newTable:SideTable){}
    };
    
    class objc_object:NSObject {
       
    };
    
    //存储所有弱引用的散列表
    lazy var SideTables : [SideTable] = {
        var sideTables:[SideTable]  = []
        for i in 0..<64{
          sideTables.append(SideTable())
        }
        return sideTables
    }() //初始化64个元素大小的SideTables数组
  
    override func viewDidLoad() {
        super.viewDidLoad()
        self.view.backgroundColor = .white
        
        
        let obj1 = NSObject()
        let obj2 = NSObject()
        weak var weakObj1:NSObject? = obj1
        weak var weakObj2:NSObject? = obj2
 
        _ =  storeWeak(location: &weakObj1!, newObj: obj1)
        _ =  storeWeak(location: &weakObj2!, newObj: obj1)
        _ =  storeWeak(location: &weakObj1!, newObj: obj2)
        
        let sideTable = side_table_for_referent(referent: obj1)
        weak_clear_no_lock(weakTable: sideTable!.weak_table!, referent: obj1)
        
        let sideTable2 = side_table_for_referent(referent: obj2)
        weak_clear_no_lock(weakTable: sideTable2!.weak_table!, referent: obj2)
    }
    

    func printLocation(location:UnsafeMutablePointer<Any>) {
        print("\(location)")
    }
   
    func storeWeak(location:UnsafeMutablePointer<NSObject>,  newObj:NSObject) -> NSObject?
    {
        let sideTable = side_table_for_referent(referent: newObj)
//        // 加锁操作,防止多线程中竞争冲突
//        SideTable.lockTwo(oldTable: oldTable!, newTable: newTable!)
       
        if isOld(location: location) {
            print("【注销】旧的弱引用指针指向的对象")
            weak_unregister_no_lock(weakTable: sideTable!.weak_table!, oldObj: newObj, location: location)
        }
        print("【注册】新的弱引用指针指向的对象")
        weak_register_no_lock(weakTable: sideTable!.weak_table!, newObj: newObj, location: location)
        
        return newObj
    }
    
    func isOld(location:UnsafeMutablePointer<NSObject>)->Bool {
        var isOld = false
        for sideTable in self.SideTables {
            for entry in sideTable.weak_table!.weakEntries {
                if entry != nil {
                    isOld = referrerIsExsit(entry: entry!, newReferrer: location)
                    if isOld == true {
                        print("【存在】弱引用地址")
                        return true
                    }
                }
            }
        }
        print("【不存在】弱引用地址")
        return false
    }
    
    
    func side_table_for_referent(referent:NSObject) -> SideTable?{
     
        let mask = SideTables.count - 1
        let begin = weakEntryHash(key: referent, mask: mask)!
        
       print("\r\n\r\n\r\n【筛选】到位置在第\(begin)的SideTable")
        return SideTables[begin]
    }
    //移除旧的弱引用
    func weak_unregister_no_lock(weakTable:WeakTableT,oldObj:NSObject,location:UnsafeMutablePointer<NSObject>){
        let entry = weak_entry_for_referent(weakTable: weakTable, referent: oldObj)
        if (entry != nil) {
            remove_referrer(entry: entry!, old_referrer: location)
        }
    }
    
    //添加新的弱引用
    func weak_register_no_lock(weakTable:WeakTableT,newObj:NSObject,location:UnsafeMutablePointer<NSObject>){
        
        var entry = weak_entry_for_referent(weakTable: weakTable, referent: newObj)
        
        let new_referrer = location
        if (entry != nil) { // 如果能找到weak_entry,则将referrer插入到weak_entry中
   
            append_referrer(entry: entry!, newReferrer: new_referrer);
        }
        else { // 如果找不到,就新建一个,并插入到weaktalbe的weakEntries数组里面
            entry = WeakEntryT(newReferent: newObj, newReferrer: new_referrer)
            weak_entry_insert(weak_table: weakTable, new_entry: entry!)
        }
    }
    
 func weak_clear_no_lock(weakTable:WeakTableT,referent:NSObject?)
    {
        let entry = weak_entry_for_referent(weakTable: weakTable, referent: referent!)
        if (entry == nil) {
            // XXX shouldn't happen, but does with mismatched CF/objc
            print("XXX no entry for clear deallocating\( referent!)")
            return
        }
  
        for referrer in entry!.inline_referrers {
            
            if referrer?.pointee == referent {
                //弱引用地址指向的对象的置为空
//                referrer?.pointee = nil
                print("弱引用地址指向的对象的置为空")
            }
        }
        weak_entry_remove(weak_table: weakTable, entry: entry!)
    }
  
    
    func weak_entry_remove(weak_table:WeakTableT, entry:WeakEntryT) {
        //清空弱引用入口
        for (i,entry1) in weak_table.weakEntries.enumerated() {
            if entry1 == entry {
               weak_table.weakEntries[i] = nil
               return
            }
        }
    }
    
    func weak_entry_insert(weak_table:WeakTableT,new_entry:WeakEntryT) {
        var weak_entries = weak_table.weakEntries
        let mask = weak_entries.count - 1
        let begin = weakEntryHash(key: new_entry.referent!, mask: mask)
        var i = begin
        repeat {
            let weakEntry = weak_entries[i!]
            if weakEntry?.referent == nil{
                print("【填充】新的入口到弱引用表中")
                weak_entries[i!] = new_entry
                weak_table.weakEntries = weak_entries
                return
            }
            i = weakEntryNext(i: i!, mask: mask)
        }while(i != begin)
 
    }
    func weak_entry_for_referent(weakTable:WeakTableT,referent:NSObject) -> WeakEntryT?{
  
        let weakEntries = weakTable.weakEntries
        let mask = weakEntries.count - 1
        let begin = weakEntryHash(key: referent, mask: mask)
        
        var i = begin
        var runCount = 0
        
        repeat {
            let weakEntry = weakEntries[i!]
            if weakEntry?.referent == referent {
                print("【找到】对应的弱引用入口")
                return weakEntry
            }
            if runCount == mask + 1 { //跑一圈没找到
                print("【没找到】对应的弱引用入口")
                return nil
            }
            i = weakEntryNext(i: i!, mask: mask)
            runCount += 1
        }while(i != begin)
        print("【没找到】对应的弱引用入口")
        return nil
    }
    
    func weakEntryNext(i:Int,mask:Int) ->Int? {
        var index = i
        if index != 0 {
            index = index - 1
            return index
        }else {
            return mask
        }
    }
    
    
    func weakEntryHash(key:NSObject,mask:Int) ->Int? {
        let keyAddr = Unmanaged.passUnretained(key as AnyObject).toOpaque()
        let keyAddrStr = "\(keyAddr)"
        let lastKeyStr = keyAddrStr.suffix(keyAddrStr.count - 2)
        let keyInt = ConvertUtil.hexTodec(number: String(lastKeyStr))
        return keyInt & mask
    }
    
    //添加弱引用
    func append_referrer(entry:WeakEntryT,newReferrer:UnsafeMutablePointer<NSObject>){
        print("【添加】弱引用地址")
        for (i, referrer) in entry.inline_referrers.enumerated()  {
            if referrer == nil {
                entry.inline_referrers[i] = newReferrer
                entry.inline_referrers[i]?.pointee = entry.referent!
                return
            }
        }
    }
 
    func remove_referrer(entry:WeakEntryT,old_referrer:UnsafeMutablePointer<NSObject>){
        print("【删除】弱引用地址")
        for (i, referrer) in entry.inline_referrers.enumerated()  {
            if referrer == old_referrer {
                entry.inline_referrers[i] = nil
                return
            }
        }
    }
    
    //inline_referrers是否存在referrr
    func referrerIsExsit(entry:WeakEntryT,newReferrer:UnsafeMutablePointer<NSObject>) -> Bool{
        
        for (i, referrer) in entry.inline_referrers.enumerated()  {
            if referrer == newReferrer{
                //元素置为空
                entry.inline_referrers[i] = nil
                return true
            }
        }
        return false
    }  
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 196,165评论 5 462
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 82,503评论 2 373
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 143,295评论 0 325
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,589评论 1 267
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,439评论 5 358
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,342评论 1 273
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,749评论 3 387
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,397评论 0 255
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,700评论 1 295
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,740评论 2 313
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,523评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,364评论 3 314
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,755评论 3 300
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,024评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,297评论 1 251
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,721评论 2 342
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,918评论 2 336