Interacting with Objective-C APIs

swift與OC交互

可以使用swift語法使用oc庫

初始化

可以使用Swift語法初始化實例。Objective-Cinit到了Swift中, init之前的alloc被去掉, initWith也被去掉。 with後面的參數首字母變成小寫, 並且變成了第一個參數的名字。 參數都用小括號括起來,名字和原來一致。

例如OC中:

OBJECTIVE-C

  • UITableView*myTableView=[[UITableViewalloc]initWithFrame:CGRectZerostyle:UITableViewStyleGrouped];

Swift中:

SWIFT

  • letmyTableView:UITableView = UITableView(frame:CGRectZero,style: .Grouped)

不需要調用 alloc; Swift 可以正確的處理這個寫法。初始化的時候並沒有出現init。

你可以顯示的寫明實例的類型,也可以不寫,swift將自己確定他的類型。

SWIFT

  • letmyTextField = UITextField(frame:CGRect(0.0,0.0,200.0,40.0))

在OC中,UITableView 和 UITextField 實例有類似的方法。你可以使用OC中類似的方法訪問他的屬性和方法。

爲了簡明一致, Objective-C和Swift工廠方法中初始化方法一致。例如以下工廠方法例子,OC中:

OBJECTIVE-C

  • UIColor*color=[UIColorcolorWithRed:0.5green:0.0blue:0.5alpha:1.0];

Swift中:

SWIFT

  • letcolor = UIColor(red:0.5,green:0.0,blue:0.5, alpha: 1.0)

訪問屬性

在swift中使用點語法來訪問屬性

SWIFT

  • myTextField.textColor = UIColor.darkGrayColor()
  • myTextField.text = "Hello world"
  • ifmyTextField.editing {
  • myTextField.editing = false
  • }

設置和訪問屬性, 使用屬性的名字(不加括號). 注意到darkGrayColor後面有括號,因爲darkGrayColor 是UIColor的方法, 而不是屬性。

在Objective-C中, 一個沒有形參有返回值的方法可以被認爲是一個 getter,可以和getter一樣的語法被調用。在swift中不是這樣,只有用 @property 語法聲明的才被認爲是屬性。 

方法的調用

Swift調用 Objective-C 的方法, 使用點語法。

Objective-C方法轉換成Swift方法時, OC方法的第一部分變成方法的名字,出現在括號的外面。第一個形參出現在括號的裏面,沒有名字。其餘的對應形參的名字,所有的都要列出來,不能被省略。

例如 Objective-C 中:

OBJECTIVE-C

  • [myTableViewinsertSubview:mySubviewatIndex:2];

Swift中:

SWIFT

  • myTableView.insertSubview(mySubview,atIndex:2)

調用的方法沒有形參,括號不能被省略。

SWIFT

  • myTableView.layoutIfNeeded()

id 兼容

Swift支持一種叫做  AnyObject 的協議類型,代表是任意類型的對象, 對應 Objective-C中的id。 AnyObject 協議允許使用在使用類型安全的Swift 語言同時兼容無類型對象的靈活性。Swift 把id 對應爲AnyObject。

例如, 同id一樣, 你可以把任意類型的對象賦值給AnyObject類型的常量和變量。

SWIFT

  • varmyObject:AnyObject = UITableViewCell()
  • myObject = NSDate()

你可以調用OC的方法和屬性而不必關心他的類型,但是方法要使用 @objc 屬性說明。

SWIFT

  • letfutureDate = myObject.dateByAddingTimeInterval(10)
  • lettimeSinceNow = myObject.timeIntervalSinceNow

因爲,只有的運行的時候才能夠直到 AnyObject 的類型, 因此容易產生錯誤。 例如,下面這個例子在運行時會產生錯誤。

SWIFT

  • myObject.characterAtIndex(5)
  • // crash, myObject does't respond to that method

可以使用Swift中得optionals 來排除錯誤。當你使用AnyObject調用OC中得方法時,實際上使用的是隱含的unwrapped optional。可以使用?來調用 AnyObject 中得方法。訪問屬性也可以用這個方法。

例如,下面的例子 length 屬性 和 characterAtIndex: 方法不存在與 NSDate 對象中。 myLength類型變成Int?, 被置爲 nil。你可以使用 iflet 有條件的展開方法的返回值。

SWIFT

  • letmyLength = myObject.length?
  • letmyChar = myObject.characterAtIndex?(5)
  • ifletfifthCharacter = myObject.characterAtIndex(5) {
  • println("Found\(fifthCharacter) at index 5")
  • }

 Swift中, AnyObject 映射成具體的類型不能保證一定會成功,因此會返回一個optional 值,你可以檢查這個值看是否成功。

SWIFT

  • letuserDefaults = NSUserDefaults.standardUserDefaults()
  • letlastRefreshDate:AnyObject? = userDefaults.objectForKey("LastRefreshDate")
  • ifletdate = lastRefreshDate as? NSDate {
  • println("\(date.timeIntervalSinceReferenceDate)")
  • }

當然,如果你確定這個類型能轉換成功,可以強制使用as。

SWIFT

  • letmyDate = lastRefreshDate as NSDate
  • lettimeInterval = myDate.timeIntervalSinceReferenceDate

使用 nil

在OC中,指向對象的指針有可能是nilI。 Swift中所有的值,包括結構體,和對象的指針都要保證是non–nil。 對於可能爲nil的聲明爲optional。 如果一個值不存在,爲nil。

因爲OC不能保證對象是非nil的,因此swift把所有從OC導入的類的 classes in argument types 和返回值都認爲是optional的。在使用之前要確定是不是nil。

如果確定不爲nil,最好也check一下。

擴展

 Swift 擴展類似於 Objective-C 類別。擴展類,結構體,枚舉類型 ,也包括已經在Objective-C中定義的。系統和自己定義的類型都可以被擴展。 Simply 導入OC定義的module, 名字和OC中得相同。

下面的例子擴展了 UIBezierPath 類。

SWIFT

  • extensionUIBezierPath {
  • convenienceinit(triangleSideLength:Float,origin:CGPoint) {
  • self.init()
  • letsquareRoot = Float(sqrt(3))
  • letaltitude = (squareRoot *triangleSideLength) / 2
  • moveToPoint(origin)
  • addLineToPoint(CGPoint(triangleSideLength,origin.x))
  • addLineToPoint(CGPoint(triangleSideLength / 2, altitude))
  • closePath()
  • }
  • }

也可以通過擴展來增加computed屬性 (包含 class 和 static properties)。  stored properties 不能被添加。

下面例子給 CGRect 增加 computed area 屬性:

SWIFT

  • extensionCGRect {
  • vararea:CGFloat {
  • returnwidth * height
  • }
  • }
  • letrect = CGRect(x:0.0,y:0.0,width:10.0, height: 50.0)
  • letarea = rect.area
  • // area: CGFloat = 500.0

可以使用擴展給類增加遵從的協議,協議使用 Swift定義, 可以在 Swift or Objective-C中使用。

不能使用擴展重定義已經有的屬性和方法。

Closures

Objective-C 中的block 自動導入成 Swift 中的closures。例如下面的Objective-C block:

OBJECTIVE-C

  • void(^completionBlock)(NSData*,NSError*)=^(NSData*data,NSError*error){/* ... */}

And here’s what it looks like in Swift:

SWIFT

  • letcompletionBlock: (NSData,NSError) -> Void = {data,errorin/* ... */}

Swift closures 和 Objective-C blocks 是兼容的, 你可以把Swift closures 傳遞給 Objective-C 方法作爲參數。 Swift closures 和 functions 類型相同, 所以也可以傳入 Swift function。

Closures 和 blocks 有一點不同: Variables are mutable rather than copied. In other words, the behavior of __block in Objective-C is the default behavior for variables in Swift.

對象比較

在 Swift中又兩種比較對象的方法:第一種, equality (==), 比較對象的內容. 第二種, identity (===), 比較常量和變量是否指向的是同一個對象。

 Swift 默認 == 比較 NSObject 的子類. 使用 NSObject 中的 isEqual 方法比較。因爲NSObject 只進行 identity 比較, 所以你需要自己重寫 isEqual: 方法。 可以在swift中實現。

要實現equality, 要有 hash 屬性 Object comparison。如果你得類要在dictionary中做key, 要遵從Hashable 協議 並且有 the hashValue 屬性。

Swift 類型兼容

如果你定義了一個從NSObject或者其他OC類繼承來得swift類, 類自動和Objective-C.兼容。swift編譯器會自動把下邊的這些步驟做了。如果你從來沒有在OC程序裏導入swift的類,你也不需要擔心兼容性。如果你得swift類沒有繼承自OC得類並且你想在OC程序中使用這個swift類的話,你可以使用 the @objc attribute。

The @objc attribute 使得你得 Swift API可以在 Objective-C 中使用。換句話說, 你可以在swift的方法,屬性和類的前面使用 @objc 屬性以便用於 Objective-C 中。 如果你的類繼承自 Objective-C class, 編譯器會自動給你插入這個屬性。 如果類被標記爲@objc 屬性的話,它的方法還有屬性都會被標記上這個屬性。 如果你使用了 @IBOutlet@IBAction, or @NSManaged 屬性, the @objc 屬性也會被添加。 當你使用OC的方法時,屬性也會被引入。

當你在 Objective-C中使用 Swift API, 編譯器會進行直接翻譯。 例如, the Swift API func playSong(name: String)會被導入成Objective-C中的 - (void)playSong:(NSString *)name。但是有例外情況: 在Objective-C中使用Swift initializer, 編譯器會在方法的前面加上“initWith”和第一個形參首字母大寫後的名字。例如, this Swift initializer init (songName: String, artist: String)被導入爲- (instancetype)initWithSongName:(NSString *)songName artist:(NSString *)artist in Objective-C.

Swift 提供 @objc 屬性更改在 Objective-C中使用的名字。例如,如果swift類的名字包含了在OC中不能使用的字符的話,可以定義成其他的名字。給swift函數起了一個OC的名字,要遵從selector語法。

SWIFT

  • @objc(Squirrel)
  • classБелка {
  • @objc(initWithName:)
  • init (имя:String) { /*...*/ }
  • @objc(hideNuts:inTree:)
  • funcпрячьОрехи(Int,вДереве:Дерево) { /*...*/ }
  • }

在swift類中使用 @objc(<#name#>) 別名的類, 不需要命名空間。 As a result, this attribute can also be useful when you migrate an archivable Objective-C class to Swift. Because archived objects store the name of their class in the archive, you should use the @objc(<#name#>) attribute to specify the same name as your Objective-C class so that older archives can be unarchived by your new Swift class.

Objective-C Selectors

An Objective-C selector is a type that refers to the name of an Objective-C method. In Swift, Objective-C selectors are represented by the Selector structure. You can construct a selector with a string literal, such aslet mySelector: Selector = "tappedButton:". Because string literals can be automatically converted to selectors, you can pass a string literal to any method that accepts a selector.

SWIFT

  • importUIKit
  • classMyViewController:UIViewController {
  • letmyButton = UIButton(frame:CGRect(x:0,y:0,width:100, height: 50))
  • init(nibNamenibNameOrNil:String!,bundlenibBundleOrNil:NSBundle!) {
  • super.init(nibName:nibName,bundle:nibBundle)
  • myButton.targetForAction("tappedButton:",withSender:self)
  • }
  • functappedButton(sender:UIButton!) {
  • println("tapped button")
  • }
  • }

NOTE

The performSelector: method and related selector-invoking methods are not imported in Swift because they are inherently unsafe.

If your Swift class inherits from an Objective-C class, all of the methods and properties in the class are available as Objective-C selectors. Otherwise, if your Swift class does not inherit from an Objective-C class, you need to prefix the symbol you want to use as a selector with the @objc attribute, as described in Swift Type Compatibility.

發佈了6 篇原創文章 · 獲贊 0 · 訪問量 8436
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章