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.