Using Swift with Cocoa and Objective-C--互用性-与ObjC API交互
2014-06-11 08:44
585 查看
https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/BuildingCocoaApps/InteractingWithObjective-CAPIs.html#//apple_ref/doc/uid/TP40014216-CH4-XID_26
http://www.cocoachina.com/newbie/basic/2014/0610/8757.html
of the first argument. The rest of the selector pieces also correspond to argument names. Each selector piece goes inside the parentheses and is required at the call site.
For example, where in Objective-C you would do this:
Objective-C
In Swift, you do this:
Swift
You don’t need to call
You can be explicit in typing the object during initialization, or you can omit the type. Swift’s type inference correctly determines the type of the object.
Swift
These
For consistency and simplicity, Objective-C factory methods get mapped as convenience initializers in Swift. This mapping allows them to be used with the same concise, clear syntax as initializers. For example, whereas in Objective-C you would
call this factory method like this:
Objective-C
In Swift, you call it like this:
Swift
Swift
When getting or setting a property, use the name of the property without appending parentheses. Notice that
In Objective-C, a method that returns a value and takes no arguments can be treated as an implicit getter—and be called using the same syntax as a getter for a property. This is not the case in Swift. In Swift, only properties that are written
using the
Working with Methods.
When Objective-C methods come over to Swift, the first part of an Objective-C selector becomes the base method name and appears outside the parentheses. The first argument appears immediately inside the parentheses, without a name. The rest
of the selector pieces correspond to argument names and go inside the parentheses. All selector pieces are required at the call site.
For example, whereas in Objective-C you would do this:
Objective-C
In Swift, you do this:
Swift
If you’re calling a method with no arguments, you must still include the parentheses.
Swift
For example, as with
Swift
You can also call any Objective-C method and access any property without casting to a more specific class type. This includes Objective-C compatible methods marked with the
Swift
However, because the specific type of an object typed as
Swift
However, you can take advantage of optionals in Swift to eliminate this common Objective-C error from your code. When you call an Objective-C method on an
For example, in the code listing below, the first and second lines are not executed because the
Swift
As with all downcasts in Swift, casting from
Swift
Of course, if you are certain of the type of the object (and know that it is not
Swift
a value is missing, you use the value
Optionals.
Because Objective-C does not make any guarantees that an object is non-nil, Swift makes all classes in argument types and return types optional in imported Objective-C APIs. Before you use an Objective-C object, you should check to ensure that
it is not missing.
In some cases, you might be absolutely certain that an Objective-C method or property never returns a
implicitly unwrapped optionals. Implicitly unwrapped optional types include all of the safety features of optional types. In addition, you can access the value directly without checking for
error occurs. As a result, you should always check and unwrap an implicitly unwrapped optional yourself, unless you are sure that the value cannot be missing.
framework or one of your own custom types. Simply import the appropriate module, and refer to the class, structure, or enumeration by the same name that you would use in Objective-C.
For example, you can extend the
Swift
You can use extensions to add properties (including class and static properties). However, these properties must be computed; extensions can’t add stored properties to classes, structures, or enumerations.
This example extends the
Swift
You can also use extensions to add protocol conformance to a class without subclassing it. If the protocol is defined in Swift, you can also add conformance to it to structures or enumerations, whether defined in Swift or Objective-C.
You cannot use extensions to override existing methods or properties on Objective-C types.
Objective-C
And here’s what it looks like in Swift:
Swift
Swift closures and Objective-C blocks are compatible, so you can pass Swift closures to Objective-C methods that expect blocks. Swift closures and functions have the same type, so you can even pass the name of a Swift function.
Closures have similar capture semantics as blocks but differ in one key way: Variables are mutable rather than copied. In other words, the behavior of
equality (
Swift and Objective-C objects are typically compared in Swift using the
As part of implementing equality for your class, be sure to implement the
Object comparison. Further, if you want to use
your class as keys in a dictionary, also conform to the
to worry about type compatibility in this case as well. Otherwise, if your Swift class does not derive from an Objective-C class and you want to use it from Objective-C code, you can use the
The
attribute to every method and property in a class that is itself marked with the
When you use a Swift API from Objective-C, the compiler typically performs a direct translation. For example, the Swift API
original initializer. For example, this Swift initializer
Swift also provides a variant of the
you can provide an alternative name to use in Objective-C. If you provide an Objective-C name for a Swift function, use Objective-C selector syntax. Remember to add a colon (
Swift
When you use the
class to Swift. Because archived objects store the name of their class in the archive, you should use the
Swift
http://www.cocoachina.com/newbie/basic/2014/0610/8757.html
Initialization
To instantiate an Objective-C class in Swift, you call one of its initializers with Swift syntax. When Objective-Cinitmethods come over to Swift, they take on native Swift initializer syntax. The “init” prefix gets sliced off and becomes a keyword to indicate that the method is an initializer. For
initmethods that begin with “initWith,“ the “With” also gets sliced off. The first letter of the selector piece that had “init” or “initWith” split off from it becomes lowercase, and that selector piece is treated as the name
of the first argument. The rest of the selector pieces also correspond to argument names. Each selector piece goes inside the parentheses and is required at the call site.
For example, where in Objective-C you would do this:
Objective-C
UITableView *myTableView = [[UITableView alloc] initWithFrame:CGRectZero style:UITableViewStyleGrouped];
In Swift, you do this:
Swift
let myTableView: UITableView = UITableView(frame: CGRectZero, style: .Grouped)
You don’t need to call
alloc; Swift correctly handles this for you. Notice that “init” doesn’t appear anywhere when calling the Swift-style initializer.
You can be explicit in typing the object during initialization, or you can omit the type. Swift’s type inference correctly determines the type of the object.
Swift
let myTextField = UITextField(frame: CGRect(0.0, 0.0, 200.0, 40.0))
These
UITableViewand
UITextFieldobjects have the same familiar functionality that they have in Objective-C. You can use them in the same way you would in Objective-C, accessing any properties and calling any methods defined on the respective classes.
For consistency and simplicity, Objective-C factory methods get mapped as convenience initializers in Swift. This mapping allows them to be used with the same concise, clear syntax as initializers. For example, whereas in Objective-C you would
call this factory method like this:
Objective-C
UIColor *color = [UIColor colorWithRed:0.5 green:0.0 blue:0.5 alpha:1.0];
In Swift, you call it like this:
Swift
let color = UIColor(red: 0.5, green: 0.0, blue: 0.5, alpha: 1.0)
Accessing Properties
Access and set properties on Objective-C objects in Swift using dot syntax.Swift
myTextField.textColor = UIColor.darkGrayColor()
myTextField.text = "Hello world"
if myTextField.editing {
myTextField.editing = false
}
When getting or setting a property, use the name of the property without appending parentheses. Notice that
darkGrayColorhas a set of parentheses. This is because
darkGrayColoris a class method on
UIColor, not a property.
In Objective-C, a method that returns a value and takes no arguments can be treated as an implicit getter—and be called using the same syntax as a getter for a property. This is not the case in Swift. In Swift, only properties that are written
using the
@propertysyntax in Objective-C are imported as properties. Methods are imported and called as described in
Working with Methods.
Working with Methods
When calling Objective-C methods from Swift, use dot syntax.When Objective-C methods come over to Swift, the first part of an Objective-C selector becomes the base method name and appears outside the parentheses. The first argument appears immediately inside the parentheses, without a name. The rest
of the selector pieces correspond to argument names and go inside the parentheses. All selector pieces are required at the call site.
For example, whereas in Objective-C you would do this:
Objective-C
[myTableView insertSubview:mySubview atIndex:2];
In Swift, you do this:
Swift
myTableView.insertSubview(mySubview, atIndex: 2)
If you’re calling a method with no arguments, you must still include the parentheses.
Swift
myTableView.layoutIfNeeded()
id Compatibility
Swift includes a protocol type namedAnyObjectthat represents any kind of object, just as
iddoes in Objective-C. The
AnyObjectprotocol allows you to write type-safe Swift code while maintaining the flexibility of an untyped object. Because of the additional safety provided by the
AnyObjectprotocol, Swift imports
idas
AnyObject.
For example, as with
id, you can assign an object of any class type to a constant or variable typed as
AnyObject. You can also reassign a variable to an object of a different type.
Swift
var myObject:AnyObject = UITableViewCell()
myObject = NSDate()
You can also call any Objective-C method and access any property without casting to a more specific class type. This includes Objective-C compatible methods marked with the
@objcattribute.
Swift
let futureDate = myObject.dateByAddingTimeInterval(10)
let timeSinceNow = myObject.timeIntervalSinceNow
However, because the specific type of an object typed as
AnyObjectis not known until runtime, it is possible to inadvertently write unsafe code. Additionally, in contrast with Objective-C, if you invoke a method or access a property that does not exist on an
AnyObjecttyped object, it is a runtime error. For example, the following code compiles without complaint and then causes an unrecognized selector error at runtime:
Swift
myObject.characterAtIndex(5)
// crash, myObject does't respond to that method
However, you can take advantage of optionals in Swift to eliminate this common Objective-C error from your code. When you call an Objective-C method on an
AnyObjecttype object, the method call actually behaves like an implicitly unwrapped optional. You can use the same optional chaining syntax you would use for optional methods in protocols to optionally invoke a method on
AnyObject. This same process applies to properties as well.
For example, in the code listing below, the first and second lines are not executed because the
lengthproperty and the
characterAtIndex:method do not exist on an
NSDateobject. The
myLengthconstant is inferred to be an optional
Int, and is set to
nil. You can also use an
if–
letstatement to conditionally unwrap the result of a method that the object may not respond to, as shown on line three.
Swift
let myLength = myObject.length?
let myChar = myObject.characterAtIndex?(5)
if let fifthCharacter = myObject.characterAtIndex(5) {
println("Found \(fifthCharacter) at index 5")
}
As with all downcasts in Swift, casting from
AnyObjectto a more specific object type is not guaranteed to succeed and therefore returns an optional value. You can check that optional value to determine whether the cast succeeded.
Swift
let userDefaults = NSUserDefaults.standardUserDefaults()
let lastRefreshDate:AnyObject? = userDefaults.objectForKey("LastRefreshDate")
if let date = lastRefreshDate as? NSDate {
println("\(date.timeIntervalSinceReferenceDate)")
}
Of course, if you are certain of the type of the object (and know that it is not
nil), you can force the invocation with the
asoperator.
Swift
let myDate = lastRefreshDate as NSDate
let timeInterval = myDate.timeIntervalSinceReferenceDate
Working with nil
In Objective-C, you work with references to objects using raw pointers that could beNULL(also referred to as
nilin Objective-C). In Swift, all values—including structures and object references—are guaranteed to be non–nil. Instead, you represent a value that could be missing by wrapping the type of the value in an optional type. When you need to indicate that
a value is missing, you use the value
nil. You can read more about optionals in
Optionals.
Because Objective-C does not make any guarantees that an object is non-nil, Swift makes all classes in argument types and return types optional in imported Objective-C APIs. Before you use an Objective-C object, you should check to ensure that
it is not missing.
In some cases, you might be absolutely certain that an Objective-C method or property never returns a
nilobject reference. To make objects in this special scenario more convenient to work with, Swift imports object types as
implicitly unwrapped optionals. Implicitly unwrapped optional types include all of the safety features of optional types. In addition, you can access the value directly without checking for
nilor unwrapping it yourself. When you access the value in this kind of optional type without safely unwrapping it first, the implicitly unwrapped optional checks whether the value is missing. If the value is missing, a runtime
error occurs. As a result, you should always check and unwrap an implicitly unwrapped optional yourself, unless you are sure that the value cannot be missing.
Extensions
A Swift extension is similar to an Objective-C category. Extensions expand the behavior of existing classes, structures, and enumerations, including those defined in Objective-C. You can define an extension on a type from either a systemframework or one of your own custom types. Simply import the appropriate module, and refer to the class, structure, or enumeration by the same name that you would use in Objective-C.
For example, you can extend the
UIBezierPathclass to create a simple Bézier path with an equilateral triangle, based on a provided side length and starting point.
Swift
extension UIBezierPath {
convenience init(triangleSideLength: Float, origin: CGPoint) {
self.init()
let squareRoot = Float(sqrt(3))
let altitude = (squareRoot * triangleSideLength) / 2
moveToPoint(origin)
addLineToPoint(CGPoint(triangleSideLength, origin.x))
addLineToPoint(CGPoint(triangleSideLength / 2, altitude))
closePath()
}
}
You can use extensions to add properties (including class and static properties). However, these properties must be computed; extensions can’t add stored properties to classes, structures, or enumerations.
This example extends the
CGRectstructure to contain a computed
areaproperty:
Swift
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
You can also use extensions to add protocol conformance to a class without subclassing it. If the protocol is defined in Swift, you can also add conformance to it to structures or enumerations, whether defined in Swift or Objective-C.
You cannot use extensions to override existing methods or properties on Objective-C types.
Closures
Objective-C blocks are automatically imported as Swift closures. For example, here is an Objective-C block variable:Objective-C
void (^completionBlock)(NSData *, NSError *) = ^(NSData *data, NSError *error) {/* ... */}
And here’s what it looks like in Swift:
Swift
let completionBlock: (NSData, NSError) -> Void = {data, error in /* ... */}
Swift closures and Objective-C blocks are compatible, so you can pass Swift closures to Objective-C methods that expect blocks. Swift closures and functions have the same type, so you can even pass the name of a Swift function.
Closures have similar capture semantics as blocks but differ in one key way: Variables are mutable rather than copied. In other words, the behavior of
__blockin Objective-C is the default behavior for variables in Swift.
Object Comparison
There are two distinct types of comparison when you compare two objects in Swift. The first,equality (
==), compares the contents of the objects. The second,identity (
===), determines whether or not the constants or variables refer to the same object instance.
Swift and Objective-C objects are typically compared in Swift using the
==and
===operators. Swift provides a default implementation of the
==operator for objects that derive from the
NSObjectclass. In the implementation of this operator, Swift invokes the
isEqual:method defined on the
NSObjectclass. The
NSObjectclass only performs an identity comparison, so you should implement your own
isEqual:method in classes that derive from the
NSObjectclass. Because you can pass Swift objects (including ones not derived from
NSObject) to Objective-C APIs, you should implement the
isEqual:method for these classes if you want the Objective-C APIs to compare the contents of the objects rather than their identities.
As part of implementing equality for your class, be sure to implement the
hashproperty according to the rules in
Object comparison. Further, if you want to use
your class as keys in a dictionary, also conform to the
Hashableprotocol and implement the
hashValueproperty.
Swift Type Compatibility
When you define a Swift class that inherits fromNSObjector any other Objective-C class, the class is automatically compatible with Objective-C. All of the steps in this section have already been done for you by the Swift compiler. If you never import a Swift class in Objective-C code, you don’t need
to worry about type compatibility in this case as well. Otherwise, if your Swift class does not derive from an Objective-C class and you want to use it from Objective-C code, you can use the
@objcattribute described below.
The
@objcattribute makes your Swift API available in Objective-C and the Objective-C runtime. In other words, you can use the
@objcattribute before any Swift method, property, or class that you want to use from Objective-C code. If your class inherits from an Objective-C class, the compiler inserts the attribute for you. The compiler also adds the
attribute to every method and property in a class that is itself marked with the
@objcattribute. When you use the
@IBOutlet,
@IBAction, or
@NSManagedattribute, the
@objcattribute is added as well. This attribute is also useful when you’re working with Objective-C classes that use selectors to implement the target-action design pattern—for example,
NSTimeror
UIButton.
When you use a Swift API from Objective-C, the compiler typically performs a direct translation. For example, the Swift API
func playSong(name: String)is imported as
- (void)playSong:(NSString *)namein Objective-C. However, there is one exception: When you use a Swift initializer in Objective-C, the compiler adds the text “initWith” to the beginning of the method and properly capitalizes the first character in the
original initializer. For example, this Swift initializer
init (songName: String, artist: String)is imported as
- (instancetype)initWithSongName:(NSString *)songName artist:(NSString *)artistin Objective-C.
Swift also provides a variant of the
@objcattribute that allows you to specify name for your symbol in Objective-C. For example, if the name of your Swift class contains a character that isn’t supported by Objective-C,
you can provide an alternative name to use in Objective-C. If you provide an Objective-C name for a Swift function, use Objective-C selector syntax. Remember to add a colon (
:) wherever a parameter follows a selector piece.
Swift
@objc(Squirrel)
class Белка {
@objc(initWithName:)
init (имя: String) { /*...*/ }
@objc(hideNuts:inTree:)
func прячьОрехи(Int, вДереве: Дерево) { /*...*/ }
}
When you use the
@objc(<#name#>)attribute on a Swift class, the class is made available in Objective-C without any namespacing. 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 theSelectorstructure. You can construct a selector with a string literal, such as
let 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
import UIKit
class 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")
}
}
相关文章推荐
- swift学习第二天 Using Swift with Cocoa and Objective-C--互用性-与ObjC API交互
- Using Swift with Cocoa and Objective-C:与 Objective-C 的 API 交互(第二部分)
- [精校版]Using Swift with Cocoa and Objective-C--互用性--Cocoa数据类型
- Using Swift with Cocoa and Objective-C--利用现有ObjC类及框架资源编写Swif
- [精校版]Using Swift with Cocoa and Objective-C--将ObjC代码迁至Swift
- iOS学习——Using Swift with Cocoa and Objective-C--在同个工程中使用Swift和在同个工程中
- [Swift A] - Using Swift with Cocoa and Objective-C--Mix and Match
- Using Swift with Cocoa and Objective-C(Swift 2.0版):开始--基础设置-备
- [精校版]Using Swift with Cocoa and Objective-C--互通性--采用Cocoa设计模
- Using Swift with Cocoa and Objective-C(Swift 2.0版):开始--基础设置
- Using Swift with Cocoa and Objective-C下载
- Using Swift with Cocoa and Objective-C--在同个project中使用Swift和在同个project中
- Using Swift with Cocoa and Objective-C
- Using Swift with Cocoa and Objective-C--在同个工程中使用Swift和在同个工程中
- Using Swift with Cocoa and Objective-C (Swift 2.1)
- Using Swift with Cocoa and Objective-C下载
- Using Swift with Cocoa and Objective-C(第一部分)
- Using Swift with Cocoa and Objetive-C
- Swift互用性:与 Objective-C 的 API 交互(Swift 2.0版更新)-备
- Swift互用性:与 Objective-C 的 API 交互(Swift 2.0版更新)