對現成的事物做延伸是人類獨有的能力,像是水可以載舟,同時也能煮粥。而程式語言也能透過延伸來替現存的物件提供拓展。
在 Swift 中,我們可以根據 Extension - Swift.org 的開頭引言,我們可以知道 Extension 可以為現存的類別拓展,尤其是當類別沒有編輯權限的時候。
Extensions add new functionality to an existing class, structure, enumeration, or protocol type. This includes the ability to extend types for which you do not have access to the original source code (known as retroactive modeling).
Extension - Swift.org
在 Objective-C 有所謂的 Category 和 Extension,在這裏我們要先告訴讀者:
Objective—C 的 Extension 不是 Swift 的 Extension
在 Extension - Swift.org 同時提到了 Swift 的 Extension 是與 Objective-C 的 Category 相似的:
Extensions are similar to categories in Objective-C. (Unlike Objective-C categories, Swift extensions do not have names.)
Extension - Swift.org
也因此我們可以知道 Category 的目的是:
提供現有的類別更多的 function。
// Objective-C
/* NSNumber+abs.h */
@interface NSNumber (abs)
- (int) absIntValue;
在 interface 後面我們為這個 category 定義一點標籤 abs
,這個標籤在使用上幾乎是沒有作用的,詳細可以參考 Do Objective-C Category names do anything? - StackOverflow。
然而在 Objective-C 有所謂的 extension, 這部分我們在 day 12 的時候其實在 /* ITPoint+internal.h */
有用到。值得注意的是,根據 Apple 官方文件 Customizing Existing Classes,我們可以知道 category 與 extension 的使用目的:
我們知道在 Swift/Objective-C 都不能直接在 Extension/Category 增加額外的 property,但是在 Objective-C 有所謂的 objc_setAssociatedObject
與 getAssociatedObject
可以得到。相關說明可以在 Category 是否可以增加新的成員變數或屬性? · KKBOX iOS_Mac OS X 基礎開發教材 理解。
在 Swift 我們可以這麼處理:
// Swift
import class Foundation.NSCache
class AssociateObject {
static let shared: AssociateObject = AssociateObject()
static func `default`() -> AssociateObject {
AssociateObject()
}
private var cache = NSCache<AnyObject, AnyObject>()
func set(_ target: AnyObject, with associateObject: AnyObject) {
cache.setObject(target, forKey: associateObject)
}
func get(_ target: AnyObject) -> AnyObject {
cache.object(forKey: target)!
}
}
拖過這樣的思想,我們可以理解 Objective-C runtime 如何達成讓類別感覺起來有新的 property。