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。
你可以使用 if
–let
有條件的展開方法的返回值。
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.