|
| 1 | +--- |
| 2 | +layout: post |
| 3 | +title: "Easy cast with _ObjectiveCBridgeable" |
| 4 | +date: 2015-10-07 19:15:43 +0200 |
| 5 | +comments: true |
| 6 | +author: rafa |
| 7 | +categories: |
| 8 | +--- |
| 9 | + |
| 10 | +Swift is out there for about a year and it's a great programming language. I think that almost every iOS/OSX developer out there has already written couple of things in Swift (if you haven't, go ahead and try, you won't regret it, I promise). Although, we have many years of libs and frameworks built using Objective-C and sooner or later a project may have both Swift and Objective-C working together. |
| 11 | + |
| 12 | +Fortunately, Apple gave us a [book](https://itunes.apple.com/us/book/using-swift-cocoa-objective/id888894773?mt=11) and a couple of WWDC session ([here](https://developer.apple.com/videos/play/wwdc2014-406/) and [here](https://developer.apple.com/videos/play/wwdc2015-401/)) with the intent to help developers on this task. |
| 13 | + |
| 14 | +For those who have some experience with this integration knows that casting plays an important role. So, todays hint will dig into an poor documented protocol called `_ObjectiveCBridgeable`. |
| 15 | + |
| 16 | +The documentation, which is only founded in header files says: |
| 17 | + |
| 18 | +> A Swift Array or Dictionary of types conforming to _ObjectiveCBridgeable can be passed to Objective-C as an NSArray or NSDictionary, respectively. The elements of the resulting NSArray or NSDictionary will be the result of calling _bridgeToObjectiveC on each element of the source container. |
| 19 | +
|
| 20 | +Ok, but there is something else you can do with that, which is very handy. |
| 21 | + |
| 22 | +Suppose that you have this class in Objective-C: |
| 23 | + |
| 24 | +```objc |
| 25 | +@interface OPerson: NSObject |
| 26 | + |
| 27 | +- (instancetype)initWithName:(NSString *)name surname:(NSString *)surname; |
| 28 | + |
| 29 | +@property (nonatomic, copy) (NSString *)name; |
| 30 | +@property (nonatomic, copy) (NSString *)surname; |
| 31 | + |
| 32 | +@end |
| 33 | +``` |
| 34 | +
|
| 35 | +Now you want to easily cast this class into a Swift struct. Yes, we can! All you have to do is conform to `_ObjectiveCBridgeable`, like so: |
| 36 | +
|
| 37 | +```swift |
| 38 | +struct Person { |
| 39 | + let name: String |
| 40 | + let surname: String |
| 41 | +} |
| 42 | +
|
| 43 | +extension Person: _ObjectiveCBridgeable { |
| 44 | +
|
| 45 | + typealias _ObjectiveCType = OPerson |
| 46 | +
|
| 47 | + static func _isBridgedToObjectiveC() -> Bool { |
| 48 | + return type |
| 49 | + } |
| 50 | +
|
| 51 | + static func _getObjectiveCType() -> Any.Type { |
| 52 | + return ObjectiveCType.self |
| 53 | + } |
| 54 | +
|
| 55 | + func _bridgeToObjectiveC() -> _ObjectiveCType { |
| 56 | + return OPerson(name: name, surname: surname) |
| 57 | + } |
| 58 | +
|
| 59 | + static func _forceBridgeFromObjectiveC(source: _ObjectiveCType, inout result: Person?) { |
| 60 | + result = Person(name: source.name, surname: source.name) |
| 61 | + } |
| 62 | +
|
| 63 | + static func _conditionallyBridgeFRomObjectiveC(source: _ObjectiveCType, inout result: Person?) -> Bool { |
| 64 | + _forceBridgeFromObjectiveC(source, result: &result) |
| 65 | + return true |
| 66 | + } |
| 67 | +} |
| 68 | +``` |
| 69 | + |
| 70 | +And voilá! |
| 71 | + |
| 72 | +```swift |
| 73 | + |
| 74 | +let objcPerson = OPerson(name: "John", surname: "Doe") |
| 75 | + |
| 76 | +if let swiftPerson = objcPerson as? Person { |
| 77 | + //will work |
| 78 | +} |
| 79 | + |
| 80 | +let swiftPerson = objcPerson as Person //this too! |
| 81 | + |
| 82 | +let swiftPerson2 = Person(name: "Jack", surname:"Doe") |
| 83 | +let objcPerson = swiftPerson2 as OPerson //and that |
| 84 | + |
| 85 | +let person: OPerson = Person(name: "Alfred", surname: "Doe") //hooray |
| 86 | +``` |
| 87 | + |
| 88 | +Oh, that's so beautiful, don't you think? :] |
0 commit comments