在 Objective-C 與 Swift 的命名有明顯的區別,雖然 Swift interface 可以將 Objective-C 的 API 以一定程度的方式改寫為 Swift 命名方式。
Photo by @jontyson on Unsplash
Objective-C 的 Foundation/Foundtion.h
提供了 NS_SWIFT_NAME
作為改寫 API 的關鍵字:
// Objective-C
NS_SWIFT_NAME(Sandwich.Preferences)
@interface SandwichPreferences : NSObject
@property BOOL includesCrust NS_SWIFT_NAME(isCrusty);
@end
@interface Sandwich : NSObject
@end
範例來自 Apple Developer Documentation [註 1]
其相對應的 Swift interface 則是
Swift interface 並不是萬能的,在提供方便的 NS_SWIFT_NAME
的同時,有幾個要避免的事情:
Sandwich.Preferences.Detail
是不能使用的// Objective-C
NS_SWIFT_NAME(Sandwich.Preferences.Detail) // 'swift_name' attribute has invalid identifier for base name
@interface SandwichPreferencesDetail : NSObject
@end
正確使用的方式是
NS_SWIFT_NAME(SandwichPreferences.Detail)
之前說到在 public header 的實作是會自動出現在 Swift interface 的,但是當我們想要透過改寫 API 的順序或是不想讓 Swift client 使用不方便的 API (如: ObjcBool 與 Swift.Bool),我們可以使用 NS_REFINED_FOR_SWIFT
的關鍵字來處理。
// Objective-C
@interface Color : NSObject
- (void)getRed:(nullable CGFloat *)red
green:(nullable CGFloat *)green
blue:(nullable CGFloat *)blue
alpha:(nullable CGFloat *)alpha NS_REFINED_FOR_SWIFT;
@end
範例來自 Apple Developer Documentation [註 2]
// Swift
extension Color {
var rgba: (red: CGFloat, green: CGFloat, blue: CGFloat, alpha: CGFloat) {
var r: CGFloat = 0.0
var g: CGFloat = 0.0
var b: CGFloat = 0.0
var a: CGFloat = 0.0
__getRed(red: &r, green: &g, blue: &b, alpha: &a)
return (red: r, green: g, blue: b, alpha: a)
}
}
請注意的是 __getRed
是不存在於 Swift interface 的。