Я пишу драйвер устройства для AV-устройства Blackmagic Design в XCode, и у меня возникают проблемы с включением класса BMD SyncController из их сокращенного примера кода (ниже) в мой проект чисто Objective-C.
Их файл DecklinkAPI.h богат кодом C ++, поэтому, когда я пытаюсь включить этот заголовочный файл как есть в класс Objective-C, компилятор задыхается глубоко в API: Неизвестное имя типа «класс»; Вы имели в виду «класс»?
Я пытался связать биты C ++ в расширение класса Obj-C, как отмечалось Вот, но без особого успеха. Я никогда не занимался программированием на C ++ (и никогда не использовал расширения классов Obj-C), поэтому для меня это новая территория.
Я не уверен, нужно ли мне создавать дополнительный класс-оболочку для моего объекта SyncController, или я могу просто сделать расширение класса для этого объекта и перетасовать биты C ++ в файл .mm.
Я хотел бы иметь возможность сделать #include "SyncController.h"
(или его оболочка) в классе Objective-C без наличия дросселя компилятора.
Любая помощь в этом будет принята с благодарностью.
Прежде всего, вот мой текущий файл SyncController.h:
#import <Cocoa/Cocoa.h>
#import "DeckLinkAPI.h" // this is rich in C++ code
class PlaybackDelegate;
@interface SyncController : NSObject {
PlaybackDelegate* playerDelegate;
IDeckLink* deckLink;
IDeckLinkOutput* deckLinkOutput;
}
- (void)scheduleNextFrame:(BOOL)prerolling;
- (void)writeNextAudioSamples;
@end
class PlaybackDelegate : public IDeckLinkVideoOutputCallback, public IDeckLinkAudioOutputCallback
{
SyncController* mController;
IDeckLinkOutput* mDeckLinkOutput;
public:
PlaybackDelegate (SyncController* owner, IDeckLinkOutput* deckLinkOutput);
// IUnknown needs only a dummy implementation
virtual HRESULT QueryInterface (REFIID iid, LPVOID *ppv) {return E_NOINTERFACE;}
virtual ULONG AddRef () {return 1;}
virtual ULONG Release () {return 1;}
virtual HRESULT ScheduledFrameCompleted (IDeckLinkVideoFrame* completedFrame, BMDOutputFrameCompletionResult result);
virtual HRESULT ScheduledPlaybackHasStopped ();
virtual HRESULT RenderAudioSamples (bool preroll);
};
void ScheduleNextVideoFrame (void);
Далее, вот мой (упрощенный) файл SyncController.mm:
#import <CoreFoundation/CFString.h>
#import "SyncController.h"
@implementation SyncController
- (instancetype)init
{
self = [super init];
return self;
}
- (void)dealloc
{
}
- (void)scheduleNextFrame:(BOOL)prerolling
{
}
- (void)writeNextAudioSamples
{
}
@end
PlaybackDelegate::PlaybackDelegate (SyncController* owner, IDeckLinkOutput* deckLinkOutput)
{
mController = owner;
mDeckLinkOutput = deckLinkOutput;
}
HRESULT PlaybackDelegate::ScheduledFrameCompleted (IDeckLinkVideoFrame* completedFrame, BMDOutputFrameCompletionResult result)
{
[mController scheduleNextFrame:NO];
return S_OK;
}
HRESULT PlaybackDelegate::ScheduledPlaybackHasStopped ()
{
return S_OK;
}
HRESULT PlaybackDelegate::RenderAudioSamples (bool preroll)
{
[mController writeNextAudioSamples];
if (preroll)
mDeckLinkOutput->StartScheduledPlayback(0, 100, 1.0);
return S_OK;
}
Я пытался связать биты C ++ в расширение класса Obj-C, как отмечалось здесь, но без особого успеха.
Если вы ориентируетесь на 64-битную версию, метод расширения класса должен быть довольно простым.
Следующее эквивалентно коду, который вы публикуете, но перемещает все объявления C ++ в отдельный заголовок:
SyncController.h:
#import <Cocoa/Cocoa.h>
@interface SyncController : NSObject
- (void)scheduleNextFrame:(BOOL)prerolling;
- (void)writeNextAudioSamples;
@end
SyncController_CPP.h
#import "SyncController.h"#include "DeckLinkAPI.h"
class PlaybackDelegate;
@interface SyncController() {
PlaybackDelegate* playerDelegate;
IDeckLink* deckLink;
IDeckLinkOutput* deckLinkOutput;
}
@end
class PlaybackDelegate ...
{
...
}
SyncController.mm
#import "SyncController_CPP.h"
@implementation SyncController
...
@end
PlaybackDelegate::PlaybackDelegate (SyncController* owner, IDeckLinkOutput* deckLinkOutput)
{
mController = owner;
mDeckLinkOutput = deckLinkOutput;
}
// etc..
Любые другие классы ObjC, которым нужен доступ к SyncController
импортирует «SyncController.h». Любые другие классы ObjC ++ могут импортировать либо «SyncController.h», либо «SyncController_CPP.h».
Не полный ответ, однако такие ошибки, как:
Неизвестное имя типа «класс»; Вы имели в виду «класс»?
Классическая проблема с Objective-C ++, где Файл реализации Objective C видит файл заголовка C ++.
Я могу только предоставить совет о том, как этого избежать, так как вы не опубликовали полный вывод сборки.
Скройте использование C ++ из любых заголовочных файлов, например, используя частные переменные экземпляра:
#import <vector>
@implementation MyObjCppClass {
std::vector<int> _stuff;
}
- (id)init {
...
}
@end
Если вы смешиваете Objective-C и Objective-C ++, то вам может потребоваться предоставить оболочки Objective-C для классов C ++ (которые выглядят снаружи как Objective-C, но на самом деле реализованы в Objective-C ++).
Переименуйте ваши .m файлы (цель-c) в .mm (цель-c ++). это должно позволить вам затем смешивать objc и c ++, включая заголовки c ++ и ссылаться на код c ++ из вашего objc.
—РЕДАКТИРОВАТЬ—
Любой заголовочный файл, который вы включаете из target-c, должен содержать только target-c. Удалите любой c ++ из заголовка в вашем классе-обертке, чтобы получить другие классы objc для сборки. В современном objc вы можете разделить свои ivars между файлами .h и .m; сохраните все ваши методы в .h для использования другими классами objc и объявите ваши c ++ ivars в .mm. Вставьте ваш класс делегата c ++ в его собственный .h, который входит только в оболочку .mm.
использование #if __cplusplus
,
Например,
#import <Cocoa/Cocoa.h>
#if __cplusplus
#import "DeckLinkAPI.h" // this is rich in C++ code
#endif // __cplusplus
@interface SyncController : NSObject {
void* playerDelegate; // should be cast as C++ PlaybackDelegate class.
...
}
@end
#if __cplusplus
class PlaybackDelegate : public IDeckLinkVideoOutputCallback, public IDeckLinkAudioOutputCallback
{
...
};
#endif // __cplusplus
Заголовочный файл может использоваться с Objective-C и Objective-C ++. Но вы не можете использовать сигнатуру класса C ++ в объявлении класса Objective-C SyncController в заголовке. использование void *
вместо PlaybackDelegate *
с правильным типом броска.
Также используя void *
означает, что материал C ++ в заголовке больше не нужен.
#import <Cocoa/Cocoa.h>
@interface SyncController : NSObject {
void* playerDelegate; // should be cast as C++ PlaybackDelegate class.
...
}
@end
В коде Objective-C ++,
// initialize
syncController.playerDelegate = new PlaybackDelegate();
// use the pointer
PlaybackDelegate *playbackDelegate = (PlaybackDelegate *)syncController.playerDelegate;
инициализировать
syncController.playerDelegate = new PlaybackDelegate();
// use the pointer
PlaybackDelegate *playbackDelegate = (PlaybackDelegate *)syncController.playerDelegate