Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to expose swift functions ONLY to objc

I have a swift framework which I'm using inside an Objective C application. I have a Location class that has the two params:

///Latitude in Decimal Degrees
public var lat : Double?

///Longitude in Decimal Degrees
public var lon : Double?

which are not accessible to Objective C because they are optionals. I'm hoping to keep a swift-only class working here so my "workaround" was to add some @objc methods for the class as well - but I don't want them to be swift accessible.

///Objective C Extensions to allow easier Access
extension LocationMessage {

@objc var getLat : Double {
    if (lat != nil) {
        return lat!
    }
    return -91;
 }

@objc var getLon : Double {
    if (lon != nil) {
        return lon!;
    }
    return -181;
}
}

So here is the question:

1) I could put this extension into the framework but is there some way to "hide" swift from being able to call it?

2) I guess I could write a swift file into my Objective C app - that adds the extensions to the class - would that be the way to go?

3) Is there another way?

like image 444
Jeef Avatar asked Sep 03 '15 20:09

Jeef


2 Answers

As of Swift 3.1, this is possible using the @available attribute. The official documentation on attributes mentions a lot of different options, but doesn't make it clear how you can combine all of them. However this Swift evolution proposal, implemented in 3.1, discusses marking something as obsolete as of a certain version of Swift:

@available(swift, obsoleted: 3.1)
class Foo {
    //...
}

In this example, trying to use the class Foo in Swift 3.1 or later will give an error. With a little adjustment, we can do this:

@available(swift, obsoleted: 1.0)
@objc(exampleMethodWithObject:)
static func exampleMethod(with object: NSObject) {
    //...
}

In this example, trying to use the method exampleMethodWithObject: in Swift 1.0 or later will give an error, whereas using it in Objective-C will not. (If you really want to be sure, you can specify obsoleted: 0.1. Using 0.0 or leaving off the version number doesn't work.)

So for your code, this should work:

extension LocationMessage {

    @available(swift, obsoleted: 1.0)
    @objc var getLat : Double {
        if (lat != nil) {
            return lat!
        }
        return -91
    }

    @available(swift, obsoleted: 1.0)
    @objc var getLon : Double {
        if (lon != nil) {
            return lon!
        }
        return -181
    }

}
like image 92
robotspacer Avatar answered Nov 12 '22 17:11

robotspacer


@available (*, unavailable) makes code unavailable to outward swift world, but @objc directive keeps it accessible by objective c.

@available (*, unavailable)
@objc public extension LocationMessage {

var getLat : Double {
    if (lat != nil) {
        return lat!
    }
    return -91;
 }

var getLon : Double {
    if (lon != nil) {
        return lon!;
    }
    return -181;
}
}
like image 40
berec Avatar answered Nov 12 '22 18:11

berec