Practice - 在 Swift 中对集合类型元素的弱引用

栏目: Swift · 发布时间: 7年前

内容简介:For more, please visit my GitHub repo:为了方便下述 Demo,这里定义一个 Pencil 类,并会使用在 Swift 中,当创建一个数组时,数组本身对于添加进去的对象元素默认是强引用(Strong),会使得其引用计数自增。

For more, please visit my GitHub repo: github.com/kingcos/Per…

Date Notes Swift Xcode
2018-03-15 更新部分表述,并将题目扩展至集合类型 4.0 9.2
2018-03-08 首次提交 4.0 9.2

Preface

为了方便下述 Demo,这里定义一个 Pencil 类,并会使用 func CFGetRetainCount(_ cf: CoreFoundation.CFTypeRef!) -> CFIndex 方法,即传入一个 CFTypeRef 类型的对象即可获取其引用计数。什么是 CFTypeRef ?查阅官方文档即可得知 typealias CFTypeRef = AnyObject ,所以 CFTypeRef 其实就是 AnyObject 。而 AnyObject 又是所有类隐含遵守的协议。

class Pencil {
    var type: String
    var price: Double
    
    init(_ type: String, _ price: Double) {
        self.type = type
        self.price = price
    }
}

CFGetRetainCount(Pencil("2B", 1.0) as CFTypeRef)
// 1

let pencil2B = Pencil("2B", 1.0)
let pencilHB = Pencil("HB", 2.0)

CFGetRetainCount(pencil2B as CFTypeRef)
CFGetRetainCount(pencilHB as CFTypeRef)
// 2 2
复制代码

What

在 Swift 中,当创建一个数组时,数组本身对于添加进去的对象元素默认是强引用(Strong),会使得其引用计数自增。

let pencilBox = [pencil2B, pencilHB]

CFGetRetainCount(pencil2B as CFTypeRef)
CFGetRetainCount(pencilHB as CFTypeRef)
// 3 3
复制代码

那么今天的问题即是,如何使得数组本身对数组元素进行弱引用?

How

WeakBox

final class WeakBox<A: AnyObject> {
    weak var unbox: A?
    init(_ value: A) {
        unbox = value
    }
}

struct WeakArray<Element: AnyObject> {
    private var items: [WeakBox<Element>] = []
    
    init(_ elements: [Element]) {
        items = elements.map { WeakBox($0) }
    }
}

extension WeakArray: Collection {
    var startIndex: Int { return items.startIndex }
    var endIndex: Int { return items.endIndex }
    
    subscript(_ index: Int) -> Element? {
        return items[index].unbox
    }
    
    func index(after idx: Int) -> Int {
        return items.index(after: idx)
    }
}
复制代码

定义好一个可以将所有类型的对象转化为弱引用的类,再通过构建好的新类型,将每个强引用元素转换为弱引用元素。利用 Extension,还可以遵守协议,扩展一些集合方法。

let weakPencilBox1 = WeakArray([pencil2B, pencilHB])

CFGetRetainCount(pencil2B as CFTypeRef)
CFGetRetainCount(pencilHB as CFTypeRef)
// 3 3

let firstElement = weakPencilBox1.filter { $0 != nil }.first
firstElement!!.type
// 2B

CFGetRetainCount(pencil2B as CFTypeRef)
CFGetRetainCount(pencilHB as CFTypeRef)
// 4 3 Note: 这里的 4 是因为 firstElement 持有(Retain)了 pencil2B,导致其引用计数增 1
复制代码

NSPointerArray

let weakPencilBox2 = NSPointerArray.weakObjects()

let pencil2BPoiter = Unmanaged.passUnretained(pencil2B).toOpaque()
let pencilHBPoiter = Unmanaged.passUnretained(pencilHB).toOpaque()

CFGetRetainCount(pencil2B as CFTypeRef)
CFGetRetainCount(pencilHB as CFTypeRef)
// 4 3

weakPencilBox2.addPointer(pencil2BPoiter)
weakPencilBox2.addPointer(pencilHBPoiter)

CFGetRetainCount(pencil2B as CFTypeRef)
CFGetRetainCount(pencilHB as CFTypeRef)
// 4 3
复制代码

A collection similar to an array, but with a broader range of available memory semantics.

Apple Documentation

NSPointerArray 比普通的 NSArray 多了一层内存语义。可以更方便的控制其中元素的引用关系,但少了 Swift 中着重强调的类型安全,所以更推荐第一种做法。

Extension

其实不只是数组,集合类型的数据结构对其中的元素默认均是强引用。所以为了更加方便地自定义内存管理方式,Objective-C/Swift 中均有普通类型的对应。但在目前的 Swift 中, NSHashTableNSMapTable 均需要指定类型,更加的类型安全(在网上的过时资料中可以看出,之前的 Swift 也没有规定需指定类型),而在 Objective-C 中只要满足 id 类型即可。

  • NSHashTable :
// NSHashTable - NSSet
let weakPencilSet = NSHashTable<Pencil>(options: .weakMemory)

weakPencilSet.add(pencil2B)
weakPencilSet.add(pencilHB)
复制代码
  • NSMapTable :
// NSMapTable - NSDictionary
class Eraser {
    var type: String
    
    init(_ type: String) {
        self.type = type
    }
}

let weakPencilDict = NSMapTable<Eraser, Pencil>(keyOptions: .strongMemory, valueOptions: .weakMemory)
let paintingEraser = Eraser("Painting")

weakPencilDict.setObject(pencil2B, forKey: paintingEraser)
复制代码
  • Objective-C:
NSHashTable *set = [NSHashTable hashTableWithOptions:NSPointerFunctionsWeakMemory];
[set addObject:@"Test"];
[set addObject:@12];
复制代码

也欢迎您关注我的微博@萌面大道V

Reference


以上所述就是小编给大家介绍的《Practice - 在 Swift 中对集合类型元素的弱引用》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Persuasive Technology

Persuasive Technology

B.J. Fogg / Morgan Kaufmann / 2002-12 / USD 39.95

Can computers change what you think and do? Can they motivate you to stop smoking, persuade you to buy insurance, or convince you to join the Army? "Yes, they can," says Dr. B.J. Fogg, directo......一起来看看 《Persuasive Technology》 这本书的介绍吧!

RGB转16进制工具
RGB转16进制工具

RGB HEX 互转工具

RGB CMYK 转换工具
RGB CMYK 转换工具

RGB CMYK 互转工具

HEX CMYK 转换工具
HEX CMYK 转换工具

HEX CMYK 互转工具