Date
Nov. 25th, 2024
 
2024年 10月 25日

Post: iOS: Easy cast with _ObjectiveCBridgeable

iOS: Easy cast with _ObjectiveCBridgeable

Published 12:07 Jul 12, 2016.

Created by @ezra. Categorized in #Programming, and tagged as #iOS.

Source format: Markdown

Table of Content

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.

Fortunately, Apple gave us a book and a couple of WWDC session (here and here) with the intent to help developers on this task.

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.

The documentation, which is only founded in header files says:

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.

Ok, but there is something else you can do with that, which is very handy.

Suppose that you have this class in Objective-C:

@interface OPerson: NSObject

- (instancetype)initWithName:(NSString *)name surname:(NSString *)surname;

@property (nonatomic, copy) (NSString *)name;
@property (nonatomic, copy) (NSString *)surname;

@end

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:

struct Person {
        let name: String
        let surname: String
}

extension Person: _ObjectiveCBridgeable {

    typealias _ObjectiveCType = OPerson

    static func _isBridgedToObjectiveC() -> Bool {
            return type
    }

    static func _getObjectiveCType() -> Any.Type {
            return ObjectiveCType.self
    }

    func _bridgeToObjectiveC() -> _ObjectiveCType {
            return OPerson(name: name, surname: surname)
    }

    static func _forceBridgeFromObjectiveC(source: _ObjectiveCType, inout result: Person?) {
            result = Person(name: source.name, surname: source.name)
    }

    static func _conditionallyBridgeFRomObjectiveC(source: _ObjectiveCType, inout result: Person?) -> Bool {
            _forceBridgeFromObjectiveC(source, result: &result)
            return true
    }
}

And voilá!

let objcPerson = OPerson(name: "John", surname: "Doe")

if let swiftPerson = objcPerson as? Person {
  //will work
}

let swiftPerson = objcPerson as Person //this too!

let swiftPerson2 = Person(name: "Jack", surname:"Doe")
let objcPerson = swiftPerson2 as OPerson //and that

let person: OPerson = Person(name: "Alfred", surname: "Doe") //hooray

That’s so beautiful, don’t you think? :]

Pinned Message
HOTODOGO
The Founder and CEO of Infeca Technology.
Developer, Designer, Blogger.
Big fan of Apple, Love of colour.
Feel free to contact me.
反曲点科技创始人和首席执行官。
开发、设计与写作皆为所长。
热爱苹果、钟情色彩。
随时恭候 垂询