For more, please visit my GitHub repo: github.com/kingcos/Per…html
Date | Notes | Swift | Xcode |
---|---|---|---|
2018-03-15 | 更新部分表述,並將題目擴展至集合類型 | 4.0 | 9.2 |
2018-03-08 | 首次提交 | 4.0 | 9.2 |
爲了方便下述 Demo,這裏定義一個 Pencil 類,並會使用 func CFGetRetainCount(_ cf: CoreFoundation.CFTypeRef!) -> CFIndex
方法,即傳入一個 CFTypeRef
類型的對象便可獲取其引用計數。什麼是 CFTypeRef
?查閱官方文檔便可得知 typealias CFTypeRef = AnyObject
,因此 CFTypeRef
其實就是 AnyObject
。而 AnyObject
又是全部類隱含遵照的協議。ios
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
複製代碼
在 Swift 中,當建立一個數組時,數組自己對於添加進去的對象元素默認是強引用(Strong),會使得其引用計數自增。git
let pencilBox = [pencil2B, pencilHB]
CFGetRetainCount(pencil2B as CFTypeRef)
CFGetRetainCount(pencilHB as CFTypeRef)
// 3 3
複製代碼
那麼今天的問題便是,如何使得數組自己對數組元素進行弱引用?github
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,還能夠遵照協議,擴展一些集合方法。web
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
複製代碼
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.swift
即 NSPointerArray
比普通的 NSArray
多了一層內存語義。能夠更方便的控制其中元素的引用關係,但少了 Swift 中着重強調的類型安全,因此更推薦第一種作法。安全
其實不僅是數組,集合類型的數據結構對其中的元素默認均是強引用。因此爲了更加方便地自定義內存管理方式,Objective-C/Swift 中均有普通類型的對應。但在目前的 Swift 中,NSHashTable
和 NSMapTable
均須要指定類型,更加的類型安全(在網上的過期資料中能夠看出,以前的 Swift 也沒有規定需指定類型),而在 Objective-C 中只要知足 id
類型便可。bash
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)
複製代碼
NSHashTable *set = [NSHashTable hashTableWithOptions:NSPointerFunctionsWeakMemory];
[set addObject:@"Test"];
[set addObject:@12];
複製代碼
也歡迎您關注個人微博 @萌面大道V數據結構