Swift与Objective-C API交互
Swift和Objective-C可以進行互操作,也就是說可以在Objective-C項目中使用Swift代碼,反過來也可以。當然,這種互操作之間最重要的是可以在Swift中調用Objective-C的接口,畢竟目前絕大部分接口都是通過Objective-C提供的。
初始化
在Swift中實例化一個Objective-C的類時,可以用Swift語法調用它的一個初始化器。Objective-C的初始化方法被分割成關鍵字。例如“initWith”變成“init”,而剩下的部分作為方法的參數名。
Objective-C的代碼:
UITableView?*myTableView?=?[[UITableView?alloc]?initWithFrame:?CGRectZero?style:?UITableViewStyleGrouped];對應的Swift代碼為:
let?myTableView:?UITableView?=?UITableView(frame:?CGRectZero,?style:?.Grouped)在Swift中不需要調用alloc方法,它會自動處理對象的創建功能。注意:Swift不會顯式的調用init方法。
定義變量或者常量的時候,可以省略它的類型,Swift會自動識別。
let?myTextField?=?UITextField(frame:?CGRect(0.0,?0.0,?200.0,?40.0))為了方便起見,Objective-C的工廠方法被映射為Swift中的初始化器。例如:
UIColor?*color?=?[UIColor?colorWithRed:?0.5?green:?0.0?blue:?0.5?alpha:?1.0];轉換為Swift:
let?color?=?UIColor(red:?0.5,?green:?0.0,?blue:?0.5,?alpha:?1.0)屬性訪問
在Objective-C和Swift中訪問屬性都是使用點操作符。
myTextField.textColor?=?UIColor.darkGrayColor() myTextField.text?=?"Hello?world"if?myTextField.editing?{myTextField.editing?=?false}訪問和設置屬性的時候不需要使用圓括號,上面darkGrayColor之所以有括號,是因為調用的是UIColor的類方法,而不是屬性。
Objective-C中不需要參數并且有一個返回值的方法,可以被當作隱含的獲取方法(getter),從而使用點操作符。但是在Swift中點操作符只能訪問Objective-C中使用@property定義的屬性。
方法調用
在Swift中使用點操作符調用Objective-C中的方法。
Objective-C的方法在Swift中調用的時候,它的第一部分成為Swift的基本方法出現在括號之前。然后函數的第一個參數沒有名字,剩下的部分作為Swift函數對應的參數名稱。
Objective-C語法:
Swift代碼:
myTableView.insertSubview(mySubview?atIndex:?2)調用無參的方法:
myTableView.layoutIfNeeded()兼容id類型
Swift包含一個叫AnyObject的協議,與Objective-C中的id類似,可以表示任意類型的對象。AnyObject協議允許你在利用無類型對象的靈活性的同時保持類型安全。
你可以給AnyObject類型的變量賦任意的值:
可以直接方法AnyObject類型對象的任意屬性和方法,而不需要進行強制類型轉換。
let?dateDescription?=?myObject.descriptionlet?timeSinceNow?=?myObject.timeIntervalSinceNow由于AnyObject類型的變量的類型需要到運行時才能確定,因此可能會導致不安全的代碼。特別是你可以訪問一個不存在的屬性或者方法,它只是在運行時報錯。
myObject.characterAtIndex(5) //crash,?myObject?doesn't?respond?to?that?method在進行類型轉換的時候,不一定轉換成功,因此Swift返回的是一個Optional值。你可以檢查是否轉換成功。
let?userDefaults?=?NSUserDefaults.standardUserDefaults()let?lastRefreshDate:?AnyObject??=?userDefault.objectForKey("LastRefreshDate")if?let?date?=?lastRefreshDate?as??NSDate?{println("\(date.timeIntervalSinceReferenceDate)") }如果你能夠確定對象的類型,并且不為nil,可以使用as操作符進行強制轉換。
let?myDate?=?lastRefreshDate?as?NSDatelet?timeInterval?=?myDate.timeIntervalSinceReferenceDatenil對象
Objective-C中使用nil來表示引用一個空對象(null)。Swift中所有的值都不會為nil。如果需要表示一個缺失的值,可以使用Optional。
由于Objective-C不能確保所有值都非空,因此Swift將Objective-C中引入的方法的參數和返回值都用Optional表示。在使用Objective-C對象之前,應該檢查它們是否存在。
擴展
Swift的擴展與Objective-C的類別有點類似。擴展能夠為已有類、結構體、枚舉等增加行為。
下面是給UIBezierPath添加擴展:
extension?UIBezierPath?{????class?func?bezierPathWithTriangle(length:?Float,?origin:?CGPoint)?->?UIBezierPath?{????????let?squareRoot?=?Float(sqrt(3))????????let?altitude?=?(squareRoot?*?length)?/?2let?myPath?=?UIBezierPath()myPath.moveToPoint(orgin)myPath.addLineToPoint(CGPoint(length,?origin.x))myPath.addLineToPoint(CGPoint(length?/?2,?altitude))myPath.closePath()return?myPath} }可以使用擴展增加屬性(包括類屬性或靜態屬性)。不過這些屬性只能是通過計算得來,而不能進行存儲。下面給CGRect添加一個area屬性:
extension?CGRect?{var?area:?CGFloat?{return?width?*?height} }let?rect?=?CGRect(x:?0.0,?y:?0.0,?width:?10.0,?height:?50.0) let?area?=?rect.area //area:?CGFloat?=?500.0使用擴展可以在不創建子類的情況下讓現有的類響應某個協議。需要注意的是,擴展不能覆蓋已有的方法和屬性。
閉包
Objective-C中的Block 被自動導入為Swift的閉包。例如:
void?(^completionBlock)(NSData?*,?NSError?*)?=?^(NSData?*data,?NSError?*error)?{????/*?...?*/}在Swift 中對應為:
let?completionBlock:?(NSData,?NSError)?->?void?=?{data,?error?in?/*?...?*/}Swift的閉包和Objective-C中的Block是兼容的,可以在Swift中給Objective-C的方法傳遞閉包來代替Block對象。
閉包和Block對象有一點不同,里面的變量是可變的,也就是說與__block修飾的變量行為相同。
對象比較
Swift中有兩種對象比較的方式。第一種是相等(==)(equality),用來比較兩個對象的內容是否相同。第二種是恒等(===)(identity),比較兩個變量或者常量是否引用同一個對象。
NSObject只能比較是否引用了同一個對象(恒等),如果要比較內容是否相同,應該實現isEqual:方法。
Swift類型兼容性
定義一個繼承自NSObject或者其他Objective-C的類,它自動與Objective-C兼容。如果你不需要將Swift對象導入Objective-C代碼的話,沒必要關注類型的兼容性。但是如果在Swift中定義的類不是Objective-C類的子類,在Objective-C中使用的時候,需要用@objc進行說明。
@objc使得Swift的API可以在Objective-C和它的運行時中使用。當使用@IBOutlet、@IBAction或者@NSManaged等屬性時,自動添加@objc屬性。
@objc還可以用來指定Swift中的屬性或方法在Objective-C中的名字,比如Swift支持Unicode名字,包括使用中文等Objective-C不兼容的字符。還有給Swift中定義的函數指定一個Selectorde名字。
@objc(Squirrel)class?長沙戴維營教育?{@objc(hideNuts:inTree:)func?歡迎光臨(Int,?姓名:?String)?{????????/*?...?*/} }當@objc(<#name#>)屬性作用在Swift的類上時,這個類在Objective-C的使用不受命名空間的限制。同樣,在Swift中解歸檔Objective-C歸檔的對象時,由于歸檔對象中存放有類名,因此需要在Swift中用@objc<#name>說明Objective-C的類名。
Objective-C選擇器(Selector)
Objective-C的選擇器是方法的一個引用。在Swift中對應的是Selector結構體。使用字符串字面量可以構建一個選擇器對象,如let mySelector: Selector = "tappedButton:"。由于字符串字面常量可以自動轉換為選擇器對象,因此可以在任何需要傳遞選擇器的地方使用字符串字面常量。
import?UIKitclass?MyViewController:?UIViewController?{????let?myButton?=?UIButton(frame:?CGRect(x:?0,?y:?0,?width:?100,?height:?50))init(nibName?nibNameOrNil:?String!,?bundle?nibBundleOrNil:?NSBundle!){super.init(nibName:?nibName,?bundle:?nibBundle)myButton.targetForAction("tappedButton:",?withSender:?self)}func?tappedButton(sender:?UIButton!)?{println("tapped?button")} }提示
performSelector:以及相關的調用選擇器的方法沒有被引入到Swfit中來,因為它們不是完全安全的。
如果Swift類繼承自Objective-C的類,則它里面的方法和屬性都能夠作為Objective-C的選擇器使用。而如果不是Objective-C的子類,需要使用@objc屬性修飾,這個在前面的Swift類型兼容性中有描述。
轉載于:https://blog.51cto.com/diveinedu/1623220
總結
以上是生活随笔為你收集整理的Swift与Objective-C API交互的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Linux内核分析--操作系统是如何工作
- 下一篇: 轻松搞定日志的可视化(第一部分)