2

I've compiled a dylib in Qt/C++. I created a simple class method called test() that reads a string input and returns a string output with "-response" back. Now how do I load that inside Objective C in XCode 7 (a default Cocoa application) and make it emit test() via NSLog()?

This is what my build folder looks like in Qt/C++.

enter image description here

Volomike
  • 23,743
  • 21
  • 113
  • 209

2 Answers2

3

You need to use an Objective-C++ class, which is a hybrid of Objective-C and C++.

The greatest challenge using one or more Objective-C++ classes in a largely Objective-C project is avoiding exposing C++ classes to the Objective-C classes. Therefore you need to avoid C++ in the Objective-C++ header file and just include the C++ in the implementation file.

For example:

CppWrapper.h:

#import <Foundation/Foundation.h>

@interface CppWrapper : NSObject
- (BOOL)callCppMethodA:(int)param;
@end

CppWrapper.mm:

#import "CppWrapper.h"
#import "cppclass.h"    // C++

@interface CppWrapper()
{
    cppclass *_cppclass;    // C++
}
@end

@implementation CppWrapper

- (id)init
{
    self = [super init];
    if (self) {
        _cppclass = new cppclass();    // C++
    }
    return self;
}

- (void)dealloc
{
    delete _cppclass;    // C++
}

- (BOOL)callCppMethodA:(int)param
{
    return _cppclass->methodA(param);    // C++
}

@end

Use it like this:

CppWrapper *cppWrapper = [CppWrapper new];
[cppWrapper callCppMethodA:123];
trojanfoe
  • 120,358
  • 21
  • 212
  • 242
  • Is the cppclass.h the header file from my Qt/C++ class? And, how do I include the dylib linkage in my ObjC project? And which file am I supposed to use -- I assume libtestlib.1.0.0.dylib? – Volomike Dec 06 '15 at 20:45
  • I'm confused. I went into XCode7 and added the libtestlib.1.0.0.dylib framework under Linked Frameworks and Libraries. Then, I added the .h file to the project. Then, in my main.m file, I added `import "testlib.h"`. It sees testlib, but the class isn't visible for some reason. All I see is: TESTLIBSHARED_EXPORT. – Volomike Dec 06 '15 at 21:04
  • 1
    Yeah sounds like you are going in the right direction with adding the `.dylib` to *Link Libraries and Frameworks*, however if `testlib.h` defines a C++ class (or functions or uses C++ classes) then you'll need to rename `main.m` to `main.mm`. – trojanfoe Dec 06 '15 at 21:12
  • I'm still stuck: http://forum.qt.io/topic/61451/how-to-call-qt-c-osx-dylib-from-objective-c/2 – Volomike Dec 07 '15 at 17:02
  • @Volomike This statement won't work: `NSLog(@"Result=%@",o->test('request'));`, assuming `o->test()` returns a `const char *` or somesuch as `%@` in the `NSLog()` format string will expect an Objective-C object. Also what is `'request'`? It's not a string is it... – trojanfoe Dec 07 '15 at 17:46
  • I have a sample download for this project, and have changed `'request'` to `"request"`. It won't compile. Perhaps you can figure it out? http://volosites.com/downloads/sample.zip – Volomike Dec 09 '15 at 04:42
  • I think I'm going to punt and try [this approach](http://stackoverflow.com/a/34184465/105539). – Volomike Dec 09 '15 at 16:53
0

Another approach would be to not use Qt/C++, but create C++ classes inside of Objective C and avoid Qt altogether, opting for these includes to make life a whole lot easier in C++:

#include <string>
#include <stdio.h>
#include <sqlite3.h>
#include <Foundation/Foundation.h>

string docs

stdio docs

stdio notes

sqlite3 docs

Apple Foundation Class docs

Also, one can (and actually must) mix a little Objective C in their C++ code in order to make life easier. Here's a sample .mm file, which is the file type that lets you mix C++ and Objective C:

#include <string>
#include <stdio.h>
#include <sqlite3.h>
#include <Foundation/Foundation.h>

class Testlib {

public:

  std::string test(std::string sIn) {
    sIn = sIn.append("-response");
    return sIn; 
  }

  NS_RETURNS_RETAINED NSString *test2(NSString *sIn) {
    // note [[funky Objective C syntax]]
    NSString *sOut = [[NSString alloc] init];
    sOut = [NSString stringWithFormat:@"%@-response", sIn];
    return sOut;
  }

};

In order for me to call this from my main.m file, I had to rename it to main.mm and then do something like:

#import <Cocoa/Cocoa.h>
#import "testlib.mm"

int main(int argc, const char * argv[]) {

  // demo Testlib out to the debug log
  Testlib *o = new Testlib();
  std::string s = "";
  s = o->test("request");
  NSLog(@"Result=%s",s.c_str());
  NSLog(@"Result2=%@",o->test2(@"request"));

  // load our GUI
  return NSApplicationMain(argc, argv);
}

So, for the most part, it gives the ease of use of C++, but makes it powerful with the SQLite3 and Apple Foundation Class stuff to do pretty much what one would have used Qt for (without having to include very large Qt runtime framework libraries). However, for the GUI -- Cocoa is pretty sparse on options (dare I say fascist) compared to Qt, which is why I opt to use Mac native WebKit inside Cocoa, which opens up a vast array of GUI styling. Also, by using Mac native WebKit instead of Qt's embedded WebKit, you can decrease the .app size by about 30MB.

Community
  • 1
  • 1
Volomike
  • 23,743
  • 21
  • 113
  • 209