8

I'm trying to run native object-c code on my Mac application.

My code looks like:

MainWindow.h:

#ifdef Q_OS_MAC
    #include <Carbon/Carbon.h>
    #include <ctype.h>
    #include <stdlib.h>
    #include <stdio.h>

    #include <mach/mach_port.h>
    #include <mach/mach_interface.h>
    #include <mach/mach_init.h>

    #include <IOKit/pwr_mgt/IOPMLib.h>
    #include <IOKit/IOMessage.h>
#endif

MainWindow.cpp:

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);


    #ifdef Q_OS_MAC
    [[[NSWorkspace sharedWorkspace] notificationCenter] addObserver: self
            selector: @selector(receiveSleepNote:)
            name: NSWorkspaceWillSleepNotification object: NULL];
    #endif

}

#ifdef Q_OS_MAC
- (void) receiveSleepNote: (NSNotification*) note
{
    NSLog(@"receiveSleepNote: %@", [note name]);
}
#endif

But am getting errors that seems that QT does not understand the code structure:

application.cpp: error: expected external declaration - (void) receiveSleepNote: (NSNotification*) note ^

Cœur
  • 37,241
  • 25
  • 195
  • 267
user3490755
  • 955
  • 2
  • 15
  • 33

1 Answers1

11

In order to compile objective-c with C++, you need to have the objective-c code in a .m or .mm file.

The accompanying header can then contain functions that can be called from C++ and the body of those functions can contain objective-c code.

So let's say, for example, we wanted to call a function to pop up an OSX notification. Start with the header: -

#ifndef __MyNotification_h_
#define __MyNotification_h_

#include <QString>

class MyNotification
{
public:
    static void Display(const QString& title, const QString& text);    
};    

#endif

As you can see, this is a regular function in a header that can be called from C++. Here's the implementation:-

#include "mynotification.h"
#import <Foundation/NSUserNotification.h>
#import <Foundation/NSString.h>

void MyNotification::Display(const QString& title, const QString& text)
{
    NSString*  titleStr = [[NSString alloc] initWithUTF8String:title.toUtf8().data()];
    NSString*  textStr = [[NSString alloc] initWithUTF8String:text.toUtf8().data()];

    NSUserNotification* userNotification = [[[NSUserNotification alloc] init] autorelease];
    userNotification.title = titleStr;
    userNotification.informativeText = textStr;

    [[NSUserNotificationCenter defaultUserNotificationCenter] deliverNotification:userNotification];
}

The implementation contains objective-c and due to its .mm file extension, the compiler will handle this correctly.

Note that in the example you provide in the question, you need to think about what the code is doing; especially when using 'self', as I expect that would need to refer to an Objective-C class, not a C++ class.

TheDarkKnight
  • 27,181
  • 6
  • 55
  • 85
  • In my Qt application [NSUserNotificationCenter defaultUserNotificationCenter] always returns nil. Do you know what might be the problem? I am using Qt 5.4.1 on OS X 10.10 – psyched Mar 30 '15 at 07:48
  • @user1113852 Sorry, with little information I couldn't tell you. I suggest starting a new SO question concerning this. – TheDarkKnight Mar 30 '15 at 08:06
  • I have posted sort of the inverse question of this -- [how to include and call a a Qt/C++ Dylib from within an Objective C Cocoa application](http://stackoverflow.com/q/34121291/105539). As of 2015 Dec 9, I'm still stuck with no answer yet, however. – Volomike Dec 09 '15 at 06:09
  • 1
    This is the best way to call objc from c++, there is a similar answer in SO with many upvotes which is too complex. – Ali Jul 20 '19 at 09:33
  • I get this when I copy the exact code and compile. ```Undefined symbols for architecture x86_64: "_OBJC_CLASS_$_NSUserNotificationCenter", "_OBJC_CLASS_$_NSUserNotification" "_OBJC_CLASS_$_NSString", referenced from:objc-class-ref in mynotification.o "_objc_msgSend", "_objc_autorelease", "_objc_alloc", referenced from: MyNotification::Display(QString const&, QString const&) in mynotification.o clang: error: linker command failed with exit code 1 (use -v to see invocation)``` – jl303 Dec 17 '19 at 03:28
  • 1
    Looks like you're not linking to the Foundation framework. – TheDarkKnight Dec 17 '19 at 13:31