Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

Add Objectice C Class to Qt project and call it from Qt C++ Class. How?



  • Hello all!

    I am trying to implement Objective C Class into Qt Project and got failed with it. Is there any step by step guidance of this process?

    The symptoms:
    -- do not see #import <Foundation/Foundation.h>
    -- showing the warning (see the attached images)
    -- at time of compiling attempt failing with errors

    2_1551009165278_Screen Shot 2019-02-24 at 14.52.15.png
    0_1551009231711_Screen Shot 2019-02-24 at 14.53.43.png
    0_1551009165277_Screen Shot 2019-02-24 at 14.50.02.png
    0_1551009722720_Screen Shot 2019-02-24 at 15.01.05.png


  • Lifetime Qt Champion

    Hi,

    Can you post the content of your Objective-C code ? Not images because it makes things tedious to test.



  • @SGaist It's very simple and working perfectly in XCode project

    Header file:

    #import <Foundation/Foundation.h>
    
    NS_ASSUME_NONNULL_BEGIN
    
    @interface ocBackend : NSObject
    
    - (void) driveAuto : (NSString *) direction;
    - (void) openTheDoor;
    - (void) pushGas;
    - (void) carMoving;
    - (void) rotateSteringWheel : (NSString *) direction;
    
    @end
    
    NS_ASSUME_NONNULL_END
    

    Class file:

    #import "ocBackend.h"
    
    @implementation ocBackend
    
    - (void) driveAuto : (NSString *) direction {
    
    	NSLog(@"driveAuto");
    
    	[self openTheDoor];
    	[self rotateSteringWheel:direction];
    	[self pushGas];
    	[self carMoving];
    }
    
    - (void) openTheDoor {
    	 NSLog(@"openTheDoor");
    }
    
    - (void) pushGas {
    	NSLog(@"pushGas");
    }
    
    - (void) carMoving {
       NSLog(@"carMoving");
    }
    
    - (void) rotateSteringWheel : (NSString *) direction {
    	if ([direction isEqualToString:@"Left"]) {
    		NSLog(@"direction is  %@",direction);
    	} else {
    		NSLog(@"rotateSteringWhel %@",direction);
    	}
    }
    
    - (NSString *) string:
    			(NSString *)vStringOne
    			StringTwo: (NSString *)vStringTwo {
    
    	NSString *vResult = [NSString stringWithFormat:@"String1: %@, String2: %@",vStringOne,vStringTwo];
    	return vResult;
    }
    
    @end
    
    

  • Lifetime Qt Champion

    How are you using ocBackend ?



  • @SGaist There was:
    -- attempt to call it from Qt/C++ class via including *.h (O-C header file) into CPP Class (look on attached image)
    -- attempt to only compile without any implementing to another C Classes (previous screenshots from this attempt)

    0_1551168128365_Screen Shot 2019-02-26 at 11.01.49.png

    It's looking like QtCreator doesn't see the MacOS libraries and don't recognise the Objective-C files.

    I found this feature Objective-C++ (as I see it's looking like mix of C++ and Objective C) but it's in Apple Archive. Could it help me?



  • @SGaist Just tried to implement this solution calling-objective-c-method-from-c-member-function

    The same result - Qt Creator do not recognise the *.mm and the Objective-C headers.0_1551190055086_Screen Shot 2019-02-26 at 17.07.22.png

    0_1551190221668_Screen Shot 2019-02-26 at 17.09.24.png

    0_1551191167467_Screen Shot 2019-02-26 at 17.25.50.png



  • I haven't found why previous not working. I am publishing the project that is working perfectly. Follow published files below. It is whole project. It has been testing on iOS. All of compiler errors was relating to hidden methods from Objective-C.

    Briefly solution looks like: declaring Objective-C methods like methods of C++ Class
    Example published in Github repository

    Additionally this project demonstrating writing custom QML component out on C++ that containing the Objective-C inclusions . The code line looks like Objective-C >>> C++ Custom QML Component >>> QML (QtQuick) Application

    My own commentary to it - it's NOT F-WORDING trivial way!!! The devil in details ... 3 days of experiments.


    experiments.pro

    QT += quick
    CONFIG += c++11
    
    # The following define makes your compiler emit warnings if you use
    # any Qt feature that has been marked deprecated (the exact warnings
    # depend on your compiler). Refer to the documentation for the
    # deprecated API to know how to port your code away from it.
    DEFINES += QT_DEPRECATED_WARNINGS
    
    # You can also make your code fail to compile if it uses deprecated APIs.
    # In order to do so, uncomment the following line.
    # You can also select to disable deprecated APIs only up to a certain version of Qt.
    #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000    # disables all the APIs deprecated before Qt 6.0.0
    
    SOURCES += \
            main.cpp \
    qmlcustomcomponent.cpp
    
    
    RESOURCES += qml.qrc
    
    # Additional import path used to resolve QML modules in Qt Creator's code model
    QML_IMPORT_PATH =
    
    # Additional import path used to resolve QML modules just for Qt Quick Designer
    QML_DESIGNER_IMPORT_PATH =
    
    # Default rules for deployment.
    qnx: target.path = /tmp/$${TARGET}/bin
    else: unix:!android: target.path = /opt/$${TARGET}/bin
    !isEmpty(target.path): INSTALLS += target
    
    HEADERS += \
    qmlcustomcomponent.h
    
    
    LIBS += -framework Foundation
    
    OBJECTIVE_SOURCES += MyNotification.mm
    OBJECTIVE_HEADERS +=  mynotification.h
    

    qmlcustomcomponent.h

    #ifndef QMLCUSTOMCOMPONENT_H
    #define QMLCUSTOMCOMPONENT_H
    
    #include <QObject>
    #include <QString>
    
    class QMLCustomComponent : public QObject {
    
    	Q_OBJECT
    	Q_PROPERTY(QString text READ text CONSTANT)
    
    	public:
    		explicit QMLCustomComponent(QObject *parent = nullptr);
    		virtual ~QMLCustomComponent();
    		QString text(void);
    
    	signals:
    
    	public slots:
    };
    
    #endif // QMLCUSTOMCOMPONENT_H
    

    main.cpp

    // System includes
    #include <QGuiApplication>
    #include <QQmlApplicationEngine>
    #include "qmlcustomcomponent.h"
    
    
    // Application includes
    
    // Constants
    const QString Main = "qrc:/main.qml";
    
    
    // QtQuick Application
    int main(int Counter, char *Arguments[]) {
    
    	QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
    	QGuiApplication Application(Counter, Arguments);
    
    	qmlRegisterType<QMLCustomComponent>("Custom.Component",1,0,"CustomComponent");
    
    	QQmlApplicationEngine Engine;
    	Engine.load(QUrl(Main));
    	if (Engine.rootObjects().isEmpty())
    		return -1;
    
    	return Application.exec();
    }
    

    mynotification.h

    #ifndef MYNOTIFICATION_H
    #define MYNOTIFICATION_H
    
    #include <QString>
    
    class MyNotification {
    
    	public:
    		static void Display(const QString& title, const QString& text);
    		static std::string Text(void);
    };
    
    
    #endif // MYNOTIFICATION_H
    

    MyNotification.mm

    #include "mynotification.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()];
    
    	NSLog(@"titleStr: %@, textStr: %@",titleStr,textStr);
    }
    
    std::string MyNotification::Text(void) {
    
    	std::string String = "String from *.mm";
    	return String;
    }
    

    qmlcustomcomponent.cpp

    #include "qmlcustomcomponent.h"
    #include "mynotification.h"
    
    
    QMLCustomComponent::QMLCustomComponent(QObject *parent)
    : QObject(parent) {
    
    }
    
    QMLCustomComponent::~QMLCustomComponent(){
    
    }
    
    QString QMLCustomComponent::text(void) {
    
    	MyNotification::Display("aaa","bbbbb");
    	QString vString = QString::fromStdString(MyNotification::Text());
    	return vString;
    }
    

    main.qml

    // System includes
    import QtQuick 2.9
    import QtQuick.Window 2.3
    import Custom.Component 1.0
    
    // Application includes
    
    
    // Application window
    Window {
    	visible: true;
    	width: 640;
    	height: 480;
    	title: qsTr("Hello World");
    
    	CustomComponent {
    		id: customComponent;
    	}
    
    	Text {
    		id: text;
    		text: qsTr(customComponent.text);
    	}
    }
    

    qml.qrc

    <RCC>
        <qresource prefix="/">
            <file>main.qml</file>
        </qresource>
    </RCC>
    

  • Lifetime Qt Champion

    The technique is: don't put anything Objective-C in the header you will you use in your C++ code. You can take a look at the QtMacExtras module to see the technique in action. Also the Cocoa backend in Qt's sources.


Log in to reply