Interoperability is a feature that makes Swift and Objective-C work together, allowing you to use files written in one language in another. When you are ready to start incorporating Swift into your development process, you should know how to take advantage of interoperability to redefine and improve the way you write Cocoa applications.
Interoperability is important because it allows you to use objective-C apis when you’re writing Swift code. When you import an Objective-C framework, you can instantiate its classes and interact with them using the native Swift syntax.
Initialize the
To instantiate an Objective-C Class using Swift, you should call one of its initializers using Swift syntax. When objective-C init methods change to Swift, they are rendered using Swift initialization syntax. The “init” prefix is truncated as a keyword indicating that the method is an initialization method. For init methods that begin With “initWith”, “With” is also removed. The part of the method name separated from “init” or “initWith” is changed to lowercase and is treated as the name of the first argument. Each of the remaining part of the method names in turn mutates the parameter names. These method names are called inside parentheses.
For example, when you use Objective-C, you do this:
1. //Objective-C
2. UITableView *myTableView = [[UITableView alloc]
3. initWithFrame:CGRectZero style:UITableViewStyleGrouped];
Copy the code
As a developer, it is particularly important to have a learning atmosphere and a communication circle. This is my iOS development public number: Programming Daxin. No matter you are a small white or a big ox, you are welcome to enter. (The group will provide some free learning books collected by the group owner and hundreds of interview questions and answer documents!)
In Swift, you should do this:
1. //Swift
2. let myTableView: UITableView = UITableView(frame: CGRectZero, style: .Grouped)
Copy the code
You don’t need to call alloc, Swift can handle it for you. Note that when using swift-style initialization functions, “init” does not appear. You can either explicitly declare the type of an object during initialization or ignore it. Swift can determine the type of an object correctly.
2. Let myTextField = UITextField(frame: CGRect(0.0, 0.0, 200.0, 40.0))Copy the code
The UITableView and UITextField objects here have the same functionality that you would use in Objective-C. You can use them in the same way, including accessing properties or calling methods in their respective classes. For uniformity and simplicity, objective-C factory methods are also mapped to convenient initialization methods in Swift. This mapping allows them to use the same neat initialization method. For example, in Objective-C you might call a factory method like this:
1. // Objective-c 2. UIColor *color = [UIColor colorWithRed:0.5 green:0.0 blue:0.5 alpha:1.0];Copy the code
In Swift, you should do this:
2. Let color = UIColor(red: 0.5, Green: 0.0, Blue: 0.5, alpha: 1.0)Copy the code
To access attributes
To access and set properties of objective-C objects in Swift, use dot syntax:
1. // Swift
2. myTextField.textColor = UIColor.darkGrayColor()
3. myTextField.text = "Hello world"
4. if myTextField.editing {
5. myTextField.editing = false
6. }
Copy the code
When a get or set property is used, the property name is used directly without parentheses. Note that darkGrayColor is followed by parentheses because darkGrayColor is a class method of UIColor, not a property.
In Objective-C, a parameterless method that returns a value can be treated as an implicit access function and can be called using the same method as the accessor. This is no longer possible in Swift, and only properties declared with the @Property keyword are introduced as properties.
methods
Use dot syntax when calling objective-C methods in Swift.
When an Objective-C method is converted to Swift, the first part of the Objective-C selector will be the method name and appear before the parentheses, the first argument will appear directly within the parentheses and have no argument name, and the rest of the argument names will be filled in one-to-one in the parentheses.
For example, when you use Objective-C, you do this:
1. //Objective-C
2. [myTableView insertSubview:mySubview atIndex:2];
Copy the code
In Swift, you should do this:
1. //Swift
2. myTableView.insertSubview(mySubview, atIndex: 2)
Copy the code
If you call a method with no parameters, you must still put a pair of parentheses after the method name
1. //Swift
2. myTableView.layoutIfNeeded()
Copy the code
Id Compatibility
Swift contains a protocol type called AnyObject, which represents an object of any type, just like an ID in Objective-C. The AnyObject protocol allows you to write type-safe Swift code while maintaining the flexibility of typeless objects. Because the AnyObject protocol guarantees this security, Swift imports the ID object as an AnyObject.
For example, just like id, you can assign an object of type AnyObject to any other type, and you can also reassign it to other types of objects.
1. //Swift
2. var myObject: AnyObject = UITableViewCell()
3. myObject = NSDate()
Copy the code
You can also call objective-C methods or access properties without converting them to the concrete class type. This includes methods in objciVE-c marked @objc.
1. //Swift
2. let futureDate = myObject.dateByAddingTimeInterval(10)
3. let timeSinceNow = myObject.timeIntervalSinceNow
Copy the code
However, because the object type of an Object is not known until run time, it is possible to inadvertently write unsafe code. Also, unlike Objective-C, if you call a method or access an AnyObject property that is not declared, you will get a runtime error. For example, the following code will present an unrecognized Selector error at runtime:
1. //Swift
2. myObject.characterAtIndex(5)
3. // crash, myObject does't respond to that method
Copy the code
However, you can use Swift’s Optinals feature to eliminate this common error in Objective-C, when you call an Objective-C method with an AnyObject, Implicitly unwrapped Optional (implicitly unwrapped Optional) action will be used for this call. You can use the optional feature to determine whether an AnyObject should call this method. Similarly, you can apply this feature to properties.
For example, in the following code, the first and second lines of code will not be executed because the Length property and characterAtIndex: method do not exist in the NSDate object. The myLength constant is presumed to be of the optional Int type and is assigned nil. You can also use the if-let declaration to conditionally expand the return value of the method to see if the object can execute the method. Just like we did in the third row.
1. //Swift 2. let myLength = myObject.length? 3. let myChar = myObject.characterAtIndex? (5) 4. if let fifthCharacter = myObject.characterAtIndex(5) { 5. println("Found \(fifthCharacter) at index 5") 6. }Copy the code
For the cast in Swift, success is not guaranteed from an object of type AnyObject to an explicit type, so it returns an optional value. You need to check whether the conversion was successful by checking the type of the value.
1. //Swift
2. let userDefaults = NSUserDefaults.standardUserDefaults()
3. let lastRefreshDate: AnyObject? = userDefaults.objectForKey("LastRefreshDate")
4. if let date = lastRefreshDate as? NSDate {
5. println("\(date.timeIntervalSinceReferenceDate)")
6. }
Copy the code
Of course, if you can determine the type of the object (and make sure it’s not nil), you can add the as operator to force the call.
1. //Swift
2. let myDate = lastRefreshDate as NSDate
3. let timeInterval = myDate.timeIntervalSinceReferenceDate
Copy the code
Use nil
In Objective-C, a reference to an object can be a primitive pointer with a value of NULL (which is also nil in Objective-C). In Swift, all values – including references to structures and objects – are guaranteed to be non-null. Instead, you wrap the nullable value as optional type. When you want to declare a value empty, you need to use nil. You can learn more about it in Optionals.
Since Objective-C does not guarantee that an object’s value is non-null, Swift, when it introduced the Objective-C API, made sure that all functions’ return types and argument types are optional. Before you use the Objective-C API, you should check to make sure that the value is non-null. In some cases, you might absolutely confirm that some objective-C method or property should never return a nil object reference. To use the IMPLICITLY unwrapped Optionals method for objects, Swift uses the IMPLICITLY unwrapped Optionals method to use objects, which contains all security features of optional types. In addition, you can access the value of an object directly without checking for nil. When accessing variables of this type, use IMPLICITLY unwrapped Optional to first check whether the value of the object does not exist. If the value of IMPLICITLY does not exist, a runtime error will be thrown.
Extensions
Swift’s extension is similar to Objective-C’s Category. Extensions enrich the functionality of existing classes, structures, and enumerations, including those defined in Objective-C. You can add extensions to the system’s framework or to your own types by importing the appropriate modules and making sure that any class, structure, or enumeration you use in Objective-C has the same name.
For example, you can extend UIBezierPath to add an equilateral triangle to it. The method simply provides the length of the triangle’s sides and the starting point.
1. //Swift
2. extension UIBezierPath {
3. convenience init(triangleSideLength: Float, origin: CGPoint) {
4. self.init()
5. let squareRoot = Float(sqrt(3))
6. let altitude = (squareRoot * triangleSideLength) / 2
7. moveToPoint(origin)
8. addLineToPoint(CGPoint(triangleSideLength, origin.x))
9. addLineToPoint(CGPoint(triangleSideLength / 2, altitude))
10. closePath()
11. }
12. }
Copy the code
You can also use extensions to add properties (both class properties and static properties). However, these properties must be computed, and extensions do not store properties for classes, structures, or enumerations. The following example adds a property called area to the CGRect class.
1. //Swift 2. extension CGRect { 3. var area: CGFloat { 4. return width * height 5. } 6. } 7. let rect = CGRect(x: 0, y: 0, width: 10.0, height: 50.0) 8. Let area = rect.area 9. // area: CGFloat = 500.0Copy the code
You can also use extensions to add protocols to a class without subclassing it. If the protocol is defined in Swift, you can add comformance to its structure or enumeration whether they are defined in Objective-C or Swift.
You cannot use extensions to override methods and properties that exist in objective-C types.
Closures
Objective-c blocks are automatically imported as closures in Swift. For example, here is a block variable in Objective-C:
1. //Objective-C 2. void (^completionBlock)(NSData *, NSError *) = ^(NSData *data, NSError *error) {/* ... * /}Copy the code
And it has the form in Swift
1. //Swift 2. let completionBlock: (NSData, NSError) -> Void = {data, error in /* ... * /}Copy the code
Swift closures work well with Objective-C blocks, so you can pass a Swift closure to an Objective-C function that takes a block as an argument. Swift closures have interworking types with functions, so you can even pass the name of the Swift function. Closures are semantically similar to blocks but differ in one place: variables can be changed directly, rather than copied, as block does. In other words, the default behavior of variables in Swift is the same as the __block variable in Objective-C.
Comparison of object
There are two ways to compare objects in two Swift’s. The first, using (==), determines whether two objects have the same content. The second, using (===), determines whether a constant or variable is an instance of the same object.
Swift and Objective-C generally use the == and === operators for comparison. Swift’s == operator provides a default implementation for objects derived from NSObject. When implementing the == operator, Swift calls the isEqual: method defined by NSObject.
The NSObject class only does the identity comparison, so you need to re-implement the isEqual: method in your own class. Since you can pass Swift objects directly to the Objective-C API, you should also implement a custom isEqual: method for those objects if you want to compare whether the contents of two objects are the same rather than just whether they are derived from the same object.
As part of implementing the comparison function, ensure that the Object’s hash property is implemented according to Object Comparison. Further, if you want your class to act as a dictionary key, you also need to follow the Hashable protocol and implement the hashValues property.
Swift Type Compatibility
When you define a Swift class that inherits from NSObject or any other Objective-C class, those classes can connect seamlessly to Objective-C. All steps are done automatically by the Swift compiler, and if you’ve never imported a Swift class into your Objective-C code, you don’t need to worry about type adaptation. On the other hand, if your Swift class does not originate from ObjectVE-c and you want to use it in objecive-c code, you can use the @objc property described below.
@objc can make your Swift API work in Objective-C. In other words, you can make any Swift method, class, or property available in objective-C code by adding @objc before them. If your class inherits from Objective-C, the compiler will do this for you automatically. The compiler will also prefix all variables, methods, and properties with @objc if the class itself is preceded by the @objc keyword. When you use an @ibOutlet, @ibAction, or @nsmanaged property, @objc is also automatically added to the front. This keyword can also be used in the target-action design pattern in objetive-c, for example, NSTimer or UIButton.
When you use the Swift API in Objective-C, the compiler basically translates the statements directly. For example, the Swift API func playSong(name: String) is interpreted as – (void)playSong (NSString *)name. However, there is one exception: When using Swift’s initializers in Objective-C, the compiler adds “initWith” to the method and capitalizes the first argument to the original initializers. For example, the Swift initialization function init (songName: String, artist: String will be translated as – (instancetype)initWithSongName:(NSString *)songName artist:(NSString *)artist.
Swift also provides a variant of the @objc keyword, which allows you to customize the names of functions converted in objectiv-c. For example, if the name of your Swift class contains characters that are not supported in Objecytive-C, you can provide an alternative name for Objective-C. If you give the Swift function an objecytive-c name, remember to add (:) to the function that takes arguments
1. 2. / / Swift @ objc (Squirrel) 3. The class Б е л seem а {4. @ objc (initWithName:) 5. The init (и м second: String) {/ *... * /} 6. @ objc (hideNuts: inTree:) 7. Func п р second discusses some related problems ь О р е х и (Int, kind guide Д е р е kind guide е : Д е р е kind guide о) {/ *... 8. * /}}Copy the code
When you use the @objc(<#name#>) keyword in a Swift class, the class can be used in Objective-C without the need for a namespace. This keyword is also useful when migrating objecive-c code to Swift. Since archived objects store the name of the class, you should use @objc(<#name#>) to declare the same name as the old archived class so that it can be unarchived by the new Swift class.
Objective-c Selectors
An Objective-C selector type refers to an Objective-C method name. In the Swift era, objective-C selectors were replaced by Selector constructs. You can create a Selector with a string, such as let mySelector: Selector = “tappedButton:”. Since strings are automatically converted to selectors, you can pass strings directly to methods that accept selectors.
1. //Swift 2. import UIKit 3. class MyViewController: UIViewController { 4. let myButton = UIButton(frame: CGRect(x: 0, y: 0, width: 100, height: 50)) 6. init(nibName nibNameOrNil: String! , bundle nibBundleOrNil: NSBundle!) { 7. super.init(nibName: nibName, bundle: nibBundle) 8. myButton.targetForAction("tappedButton:", withSender: self) 9. } 11. func tappedButton(sender: UIButton!) { 12. println("tapped button") 13. } 14. }Copy the code
Note: The performSelector: method and related methods that call the selector are not imported into Swift because they are unsafe.
As a developer, it is particularly important to have a learning atmosphere and a communication circle. This is my iOS development public number: Programming Daxin. No matter you are a small white or a big ox, you are welcome to enter. (The group will provide some free learning books collected by the group owner and hundreds of interview questions and answer documents!)
If your Swift class inherits from an Objective-C class, all of your methods can be used as objective-C selectors. Also, if your Swift class is not inherited from Objective-C, you’ll need to add the @objc keyword in front of it if you want to use it as a selector. See Swift Type Compatibility for more details.