Interacting with Objective-C APIs(與OC-API的交互)###
Initialization(初始化)####
要使用Swift初始化一個Objecive-C的類,只要使用Swift調(diào)用這個類的其中一個構造函數(shù)。
OC通常使用init
初始化,或者如果實例對象需要帶一個或多個參數(shù)使用initWith:
,當OC的初始化轉化為Swift,init
前綴是一個關鍵字,暗含了Swift初始化方法。如果初始化帶一個參數(shù),With
從選擇器的后邊移除之后成為相應的命名參數(shù)。
下面是OC的初始化聲明:
- (instancetype)init;
- (instancetype)initWithFrame:(CGRect)frame
style:(UITableViewStyle)style;
相同的Swift初始化聲明:
init() {/*...*/}
init(frame: CGRect, style: UITableViewStyle) {/*...*/}
在初始化的時候OC和Swift還是有明顯不同的.
在OC中,你這么做:
UITableView *myTableView = [[UITableView alloc] initWithFrame:CGRectZero style:UITableViewStyleGrouped];
在Swift中,你這么做:
let myTableView: UITableView = UITableView(frame: CGRectZero, style: .Grouped)
注意你不需要調(diào)用alloc
;Swift會自動為你處理。當調(diào)用Swift初始化的時候也不會出現(xiàn)init
.
當你給一個常量或變量賦值的時候,你可以明確的標明類型,或者你也可以去掉類型,Swift可以從初始化自動推理類型.
let myTextField = UITextField(frame: CGRect(x: 0.0, y: 0.0, width: 200.0, height: 200.0))
Class Factory Methods and Convenience Initializers(類工廠方法和方便的初始化)####
對于連貫性和簡便性,在Swift中OC的類工廠方法是重要的簡便的。初始化允許他們用相同的編譯器。
例如,在OC中你可以這樣調(diào)用工廠方法:
UIColor *color = [UIColor colorWithRed:0.5 green:0.0 blue:0.5 alpha:1.0];
在Swift中,你可以這么調(diào)用:
let color = UIColor(red: 0.5, green: 0.0, blue: 0.5, alpha: 1.0)
Failable Initialization(可失敗的初始化)####
在OC中,直接初始化返回初始化對象。當初始化失敗的時候為了通知調(diào)用者,OC的初始化可以返回nil.在Swift中,這個模式被構建為語言特性叫做failable initialization(可失敗的初始化)
許多OC的初始化在系統(tǒng)的framework被審查用來表明初始化是否可能失敗.你可以在自己的類用空指針表明初始化是否失敗,描述在這里 Nullability and Optionals.OC初始化表明是否失敗等同于init(...)
表明如果初始化不失敗,或者init?(...)
表明如果初始化失敗.另外,OC初始化也可以為init!(...)
.
例如,UIImage(contentsOfFile:)
初始化可能失敗,如果提供的路徑圖片不存在.如果初始化是成功的你可以使用可選值綁定對失敗的結果進行解包.
if let image = UIImage(contentsOfFile: "MyImage.png") {
// loaded the image successfully
} else {
// could not load the image
}
Accessing Properties(訪問屬性)####
OC用@property屬性聲明和下列Swift的屬性聲明是一樣的:
- Properties用
(nonnull, nullable, null_resettable)
的空屬性等同于Swift在Nullability and Optionals可選或不可選類型. - Properties用
readonly
標記的屬性等同于Swift的getter{ get }
. - Properties用
weak
標記的屬性等同于Swift用weak
關鍵字標記(weak
). - 所有的屬性并非都是
weak
(也有assign, copy, strong , unsafe_unretained
)等同于Swift有關的存儲屬性. - Properties用
class
屬性等同于Swift的屬性 - Atomicity屬性(
atomic
和nonatomic
)不會在Swift的屬性聲明中響應,但是當Swift的重要的屬性訪問得時候,OC的原子性保護依然保持. - 在Swift訪問屬性(
getter=
和setter=
)被忽略.
OC對象在Swift中訪問屬性,用屬性名不帶括號.
例如,你可以設置用如下代碼UITextField
的textColor
和text
:
myTextField.textColor = UIColor.darkGray()
myTextField.text = "Hello World"
Working with Methods###
在Swift中,你可以調(diào)用OC的方法使用點語法.
當OC的方法轉化為Swift時,OC選擇器的第一部分會成為方法名并且出現(xiàn)在括號前。第一個參數(shù)將直接在括號里邊,并且沒有名字。余下的參數(shù)名與參數(shù)則一一對應的填在括號中。
例如,在OC中你可以這么做:
[myTable insertSubview:mySubview atIndex:2];
在Swift中,你可以這么做:
myTableView.insertSubview(mySubview, at: 2)
如果你調(diào)用無參方法,你必須加上括號。
myTableView.layoutIfNeeded()
id Compatibility###
Swift包含一個AnyObject
的協(xié)議對象,這個就好比是OC的id
類型。AnyObject 協(xié)議可以讓你寫出類型安全的代碼的同時維持無類型對象的通用性。因為AnyObject協(xié)議保證了這種安全,Swift將id對象導入為AnyObject。
例如,id
,你可以為AnyObject類型的對象分配任何其他類型的對象。你也同樣可以為它重新分配其他類型的對象。
var myObject: AnyObject = UITableViewCell()
myObject = NSDate()
你也可以在調(diào)用Objective-C方法或者訪問屬性時不將它轉換為具體類的類型。包括Objcive-C中標記為@objc的方法。
let futureDate = myObject.addingTimeInterval(10)
let timeSinceNow = myObject.timeIntervalSinceNow
Unrecognized Selectors and Optional Chaining###
因為AnyObject
對象的類型只有在運行時才能知道,所以我們不經(jīng)意間,就寫出了不安全的代碼。另外,與Objective-C不一樣的是,如果你調(diào)用方法或者訪問的屬性AnyObject
對象沒有聲明,將會報運行時錯誤。例如,下面的代碼將會在運行時拋出unrecognized selector error
myObject.character(at: 5)
// crash, myObject doesn't respond to that method
盡管如此,你也可以借助Swift的optionals特性來排除這個Objective-C中常見的錯誤,當你用AnyObject對象調(diào)用一個Objective-C的方法,這次調(diào)用將會變成一次隱式展開optional(implicitly unwrapped optional)的行為。你可以通過optional特性來決定AnyObject類型的對象是否調(diào)用該方法,同樣的,你可以把這種特性應用在屬性上。
例如,在下列代碼,第一行和第二行不會檢查,因為count
屬性和character(at:)
方法在NSDate
對象不存在。myCount
被推測為一個可選的Int
類型,并且被設置為nil
.你可以使用if-let
聲明來展開這個方法的返回值,就像第三行一樣:
// myObject has AnyObject type and NSDate value
let myCount = myObject.count
/// myCount has Int? type and nil value
let myChar = myObject.character?(at: 5)
// myChar has unichar? type and nil value
if let fifthCharacter = myObject.character?(at: 5) {
print ("Found \(fifthCharacter) at index 5")
}
// conditional branch not executed
Downcasting AnyObject###
在處理泛型,類型是已知或可以合理肯定的時候,把這些對象轉為更具體的類型。然而,因為泛型可能是任意一種類型,不一定能夠成功的轉為具體的類型。
你可以用條件類型轉化操作(as?
),它可以返回一個你嘗試轉化類型的可選值:
let userDefaults = UserDefaults.standard
let lastRefreshDate: AnyObject? = userDefaults.object(forKey: "LastRefreshDate")
if let date = lastRefreshDate as? NSDate {
print("\(date.timeIntervalSinceReferenceDate)")
}
如果你確定對象類型,你可以使用強轉操作(as!
)代替。
let myDate = lastRefreshDate as! NSDate
let timeInterval = myDate.timeIntervalSinceReferenceDate
然而,如果強制轉化失敗,運行時會出錯:
let myDate = lastRefreshDate as! NSString //Error
Nullability and Optionals###
在OC中,你引用的對象的原始指針可能為NULL
(也可能為nil
)。在Swift中,所有的值–包括結構體與對象的引用–都被保證為非空。作為替代,你將這個可以為空的值包裝為optional type。當你需要指示該值為空,你需要使用nil,你可以閱讀更多關于Optionals的內(nèi)容。
OC可以用空指針來指定參數(shù)類型,屬性類型,或者返回類型,也可以用NULL
或 nil
。單獨的類型聲明用_Nullable
和_Nonnull
指針可能被檢查,單獨的屬性聲明用nullable
,nonnull
和null_resettable
屬性可能被檢查,或者全部使用NS_ASSUME_NONNULL_BEGIN
和NS_ASSUME_NONNULL_END
宏都可能被檢查。如果一個類型不是空信息,Swift不會區(qū)分可選與不可選的,作為隱形解析可選。
- 類型聲明為非空,帶
_Nonnull
指針或在檢查區(qū)域,在Swift中是不可選的。 - 類型聲明為空,帶
_Nullable
指針,在Swift中可選。 - 類型聲明不帶空指針,在Swift是一個隱士解析可選
例如,看下列OC聲明:
@property (nullable) id nullbaleProperty;
@property (nonnull) id nonNullProperty;
@property id unannotatedProperty;
NS_ASSUME_NONNULL_BEGIN
- (id)returnsNonNullValue;
- (void)takesNonNullParameter:(id)value;
NS_ASSUME_NONNULL_EDN
- (nullable id)returnsNullableValue;
- (void)takesNullableParameter:(nullable id)value;
- (id)returnsUnannotatedValue;
- (void)takesUnannotatedParameter:(id)value;
Swift寫法:
var nullableProperty: AnyObject?
var nonNullProperty: AnyObject
var unannotatedProperty: AnyObject!
func returnsNonNullValue() -> AnyObject
func takesNonNullParameter(value: AnyObject)
func returnsNullableValue() -> AnyObject?
func takesNullableParameter(value: AnyObject?)
func returnsUnannotatedValue() -> AnyObject!
func takesUnannotatedParameter(value: AnyObject!)
大多OC的系統(tǒng)frameworks,包含F(xiàn)oundation,早已提供空注釋,允許
你慣用和類型安全的方式使用值。
未完待續(xù)...