Как совместно использовать объект Swift среди проектов Objective-C в Xcode workspace?

#c #ios #objective-c #swift #xcode

#c #iOS #objective-c #swift #xcode

Вопрос:

TLDR: в рабочей области есть два проекта. В одном проекте есть экземпляр объекта Swift, который реализует протокол Objective-C. Как разделить его между двумя проектами в рабочей области и сделать его доступным в файлах mm в этих проектах?

У меня есть рабочее пространство с 2 проектами A и B, где B — это фреймворк, а A зависит от него. Мне нужно совместно использовать объект Swift, созданный в A, среди A и B. Я пытался сделать это со статической переменной и с реализацией класса, но потерпел неудачу — кажется, что каждый из проектов получает свою собственную версию всего. У меня почти нет опыта работы с C и Objective-C / Swift, поэтому я могу упустить что-то очевидное.

Вот как выглядит мой код:

 // [ Project A, file Header.h ]

#ifndef Header_h
#define Header_h

// the Swift object must extend this protocol
@protocol CallsProxySingleton
-(void) someImportantMethod
@end

// --- way 1 of attempting to pass the instance: static variable

id<CallsProxySingleton> variableInstance = NULL;

void SetVariableInstance(id<CallsProxySingleton> api) {
    variableInstance = api;
}

// --- way 2 of attempting to pass the instance: class

@interface FrameworkLibApi : NSObject
 (void) registerAPIForNativeCalls:(id<CallsProxySingleton>) aApi;
@end

// this is used from Swift to install the singleton instance
@implementation FrameworkLibApi
static id<CallsProxySingleton> api = NULL;
 (void) registerAPIForNativeCalls:(id<CallsProxySingleton>) aApi {
    api = aApi;
}
 (id<CallsProxySingleton>) getApi {
    return api;
}
 (instancetype) getSelf {
    return self;
}
@end

#endif
  
 // [ Project A, file CallsProxySingletonSwiftImplementation.swift ]

class CallsProxySingletonSwiftImplementation : NSObject, CallsProxySingleton {
    func initialize() {
        // --- way 1
        SetVariableInstance(self)
        // --- way 2
        NSClassFromString("FrameworkLibApi")!.registerAPIForNativeCalls(self)
    }

    // implementing CallsProxySingleton
    func someImportantMethod() {} 
}
  
 // [ Project A, file NativeInterfaceA.mm ]

extern "C" void SomeMethodThatsCalledFromCppCode() {
    // !!! this prints correct values: all pointers are non-null after the CallsProxySingletonSwiftImplementation had been called
    NSLog("pointers A: variable=%p, framework.api=%p, framework.self=%p", variableInstance, [FrameworkLibApi getApi], [FrameworkLibApi getSelf])
}

  
 // [ Project B, file NativeInterfaceB.mm ]

extern "C" void SomeOtherMethodThatsCalledFromCppCode() {
    // !!! this prints all null pointers (0x0) except for [FrameworkLibApi getSelf] which prints a different pointer than in project A
    NSLog("pointers B: variable=%p, framework.api=%p, framework.self=%p", variableInstance, [FrameworkLibApi getApi], [FrameworkLibApi getSelf])
}

  

Распечатка выглядит следующим образом:

 pointers A: variable=0x281e98980, framework.api=0x281e98980, framework.self=0x102bf6c88
pointers B: variable=0x0, framework.api=0x0, framework.self=0x10d6352c0
  

Итак, все это выглядит так, как будто мой файл заголовка повторно интерпретируется дважды, и второй его «экземпляр», скомпилированный в проекте B, имеет свой собственный набор переменных, который совершенно не связан с переменными в проекте A. [FrameworkLibApi getSelf] Возврат другого указателя только подтверждает это предположение. Ни установка глобальной переменной, ни класса не помогли совместно использовать переданный экземпляр. С точки зрения организации рабочего пространства Xcode, [ Project A, file Header.h ] файл добавляется в проект B по ссылке без копирования.

В качестве третьего способа я также попытался переместить [ Project A, file Header.h ] файл в отдельный проект C и сделать проекты A и B зависимыми от framework C, но это дало абсолютно тот же результат.

Вопрос: Как мне совместно использовать предполагаемый одноэлементный экземпляр объекта Swift для проектов в рабочей области?