Paolo Pascua
Paolo Pascua

Reputation: 123

Objective C Singleton method not available in Swift Interface

I've been looking for documents of reasons of why a singleton method definition in Objective-C class is not available on the Swift interface on Xcode.

The Objective-C class is defined like this

/**
 * A general accessor across the sample App to remove the dependency of QPSLibraryManager from resusable components.
 */
@interface QPSSharedAccessor : NSObject

/**
 * Required by QPSLibraryManager and some UI components.
 */
@property (nonatomic, strong) QPSApplicationConfiguration *qpsConfiguration;

/**
 * Provides Commands to app
 */
@property (nonatomic, strong) id<QPSAppController> appController;;

/**
 * Shared singleton.
 */
+ (instancetype)sharedAccessor;

/**
 * Returns access to a configuration manager
 */
- (QPSConfigurationManager *)configurationManager;

@end

On Swift Interface, its defined like this

/**
 * A general accessor across the sample App to remove the dependency of QPSLibraryManager from resusable components.
 */
open class QPSSharedAccessor : NSObject {


    /**
     * Required by QPSLibraryManager and some UI components.
     */
    open var qpsConfiguration: QPSApplicationConfiguration!


    /**
     * Provides Commands to app
     */
    open var appController: QPSAppController!


    /**
     * Returns access to a configuration manager
     */
    open func configurationManager() -> QPSConfigurationManager!
}

I'm expected to see the sharedAccessor() singleton method on Swift but it is missing as you can see. Calling the said method on a separate swift file results in a compiler error, saying that the sharedAccessor() method doesn't exist. Converting everything to Swift is not viable btw. Advice on fixing this problem?

Upvotes: 1

Views: 812

Answers (1)

Anatoli P
Anatoli P

Reputation: 4891

After some experimentation, I see that sharedAccessor() appears to have some special meaning. Using a different name for it, e.g. sharedAccessor1() or sharedInstance(), worked for me just fine. One related observation is that trying to call sharedAccessor() when it is NOT part of the interface results in this error: Type QPSSharedAccessor has no member sharedAccessor, which makes sense. However, adding sharedAccessor() to the Objective-C code results in:

'sharedAccessor()' is unavailable: use object construction 'QPSSharedAccessor()'

Opening the error details sheds more light on this:

'sharedAccessor()' has been explicitly marked unavailable here (__ObjC.QPSSharedAccessor)

Now, renaming the QPSSharedAccessor type to something else makes sharedAccessor() acceptable, but if the new type name is, for example, QPSMyClass, then naming the method myClass() becomes a problem!

To work around this strange problem, evidently having to do with compiler internals, obscure method naming conventions, or a bug, you can simply rename the sharedAccessor() method to something else. Alternatively, you can write a wrapper method in C or Objective-C and make it available to Swift via the bridging header. For example:

QPSSharedAccessor * getGlobalQPSSharedAccessor()
{
    return [QPSSharedAccessor sharedAccessor];
}

You could also add a category to QPSSharedAccessor with a method having a different name and delegating to sharedAccessor().

Also, please see if these references are useful:

Can't build in Xcode with error "[method] has been explicitly marked unavailable"

https://developer.apple.com/library/content/documentation/Swift/Conceptual/BuildingCocoaApps/AdoptingCocoaDesignPatterns.html (see the Singleton section).

Upvotes: 1

Related Questions