0

I have written a Objective C++ wrapper so that I will be able to access the C++ methods in Swift.

The wrapper has a method which returns a C++ class reference.

IECMServices.h (C++ class)

namespace ECMServices
{
    class IECMServices
    {
    public:
        virtual DataServices::IParameters& getDeviceInformation(ECMServicesTypes::UINT_16 moduleID) = 0;

    };
}

IECMServicesWrapper.mm (Objective C++ class)

I am getting the above error while writing the Wrapper code.

IParameters is a C++ class OParameters is Objective C++ equivalent class for IParameters

I want to return reference of OParameters to Swift. For that I want to pass reference of C++ class to my oParametersRef

oParametersRef = oCECMServicesProviderObj.getECMServices().getDeviceInformation(0);

"oCECMServicesProviderObj.getECMServices().getDeviceInformation(0);"

this returns reference of IParameters which is a C++ class.

So that i can access methods of IParameters(C++) in swift via OParameters(Objective C++)

I want to pass reference of C++ to Objective C++ to Swift.

harish
  • 21
  • 3

1 Answers1

0

Search this community site, there are many answers that address this problem. See, for example, this: How to use Superpowered lib in Swift project

The specific error message in the image is due to the fact that getDeviceInformation() returns a reference to IParameters, which is assigned to an incompatible type OParameters*, i.e. a pointer to OParameters. The code of OParameters is not given, but I would guess that converting an IParameters reference to an OParameters pointer would be tricky and unnecessary. Anyway, your OParameters class evidently does not provide such a conversion.

As you can see in the aforementioned answer, it is impossible to expose C++ code to Swift directly, and IParameters is a C++ class. Objective-C++ allows you to mix Objective-C and C++, but only the Objective-C portion of the code can be exposed to Swift through headers. So, you will need to create an Objective-C class that is populated based on the contents of an IParameters instance and returned to Swift. In addition, if you want changes made in Swift to be visible in C++, you would need to keep a pointer or a reference to IParameters in the wrapper .mm file, but NOT in any headers visible to Swift, and have setters, visible to Swift, that can be used to modify the IParameters state.

Here is a quick and dirty example. The focus here is only on sharing IParams between C++ and Swift. Things like memory management are out of scope here. For simplicity, let us say our IParams and EMC C++ classes look as follows:

class IParams {
public:
    int32_t param1;
    int32_t param2;
};

class ECM
{
public:
    static ECM * getInstance();   
    // It's very important that a reference is returned here.  This
    // allows us to store the pointer to the referenced IParams in a
    // member of OParams, and the OParams' getters and setters can then
    // directly access the IParams object returned here by reference. 
    IParams& getDeviceInfo(); 
...
};

Here are their wrapper implementations in Objective-C++ (.mm) code, which refer to C++ code directly, but it's OK as this is hidden from Swift:

@implementation OParams
{
    IParams * pIParams;  
}

-(id)init:(IParams*)pip
{
    pIParams = pip;
    return self;
}

// These getters and setters directly access the memory of the IParams
// object pointed to by pIParams.
-(int32_t)getParam1 { return pIParams->param1; }
-(int32_t)getParam2 { return pIParams->param2; }
-(void)setParam1:(int32_t)p { pIParams->param1 = p; }
-(void)setParam2:(int32_t)p { pIParams->param2 = p; }

@end

@implementation ECMWrapper

-(OParams*)getDeviceInfo
{
    // We're returning a pointer to an OParams instance whose pIParams 
    // member points to the IParams object the reference to which is
    // returned from ECM::getDeviceInfo()
    return [[OParams alloc] init:(&ECM::getInstance()->getDeviceInfo())];
}

@end

Finally, here are the declarations that are visible to Swift, directly or indirectly, via the bridging header:

@interface OParams : NSObject

-(int32_t)getParam1;
-(int32_t)getParam2;
-(void)setParam1:(int32_t)p;
-(void)setParam2:(int32_t)p;

@end

@interface ECMWrapper : NSObject

-(OParams*)getDeviceInfo;

@end

Note that no C++ types or methods are mentioned here, so this code can be used in Swift.

Community
  • 1
  • 1
Anatoli P
  • 4,791
  • 1
  • 18
  • 22
  • here is the OParameters Class- @implementation OParameters DataServices::IParameters *oIParametersObj; -(DataServices::IParameter *) get:(int) iIndex_In { DataServices::IParameter *refIParameterObj; refIParameterObj = &oIParametersObj->get(iIndex_In); return refIParameterObj; } -(unsigned long) getCount { // DataServices::IParameters& objISystem = oCECMServicesProviderObj.getECMServices().getDeviceInformation(0); // return objISystem.getCount(); return 1; } – harish May 19 '16 at 13:02
  • IParameters Class- class IParameters { public: virtual ECMServicesTypes::UINT_32 getCount(void) = 0; virtual DataServices::IParameter& get(ECMServicesTypes::UINT_32 iIndex_In) = 0; }; – harish May 19 '16 at 13:06
  • Could you please explain how to populate contents of OParameters with IParameters instance.. Also how to keep a pointer reference to IParameters in wrapper .mm, so that I can track changes made in swift. – harish May 19 '16 at 13:09
  • Ok. I have got it working this way. But passing by reference from Objective C++ to Swift will be a better approach rather than pass by copy. So need help on how to pass it by reference. – harish May 19 '16 at 17:50
  • I don't think you can make a C++ object reference directly available to Swift code. However, wrapping the reference in an Objective-C++ class with appropriate setters and getters and providing it to Swift is functionally the same as giving it a reference. Have you figured it out already? If not, I can come up with a simplified example. – Anatoli P May 20 '16 at 00:52
  • Apple docs say: "You cannot import C++ code directly into Swift. Instead, create an Objective-C or C wrapper for C++ code." See https://developer.apple.com/library/ios/documentation/Swift/Conceptual/BuildingCocoaApps/. Also, looking at `IParameters` and `OParameters`, I see another problem: `get()` in `OParameters` returns `IParameter*`, which is again a pointer to a C++ class and is unusable in Swift. One option is to wrap it in yet another Objective-C class. – Anatoli P May 20 '16 at 01:50
  • Yes, a more simplified example would help to get more understanding. – harish May 20 '16 at 18:12
  • I added one yesterday, hopefully it helps. There are lots of other things to worry about, such as memory management, object lifetime, etc., but those deserve separate questions if you run into problems. – Anatoli P May 20 '16 at 19:54