Ошибка при включении классов Apple ClassKit и swift в существующее приложение с классами Objective-C ++ и C ++ в файлах .mm - PullRequest
0 голосов
/ 21 января 2019

Я делаю тестовый проект, чтобы увидеть, можно ли включить Apple ClassKit для школ в существующее учебное приложение ios с классами Objective-C ++ и C ++ в файлах .mm, и я получаю сообщение об ошибке в ...- Swift.h bridging header (автоматически создается xcode при добавлении файла swift), даже перед импортом bridging header в файлы ObjectiveC ++, чтобы предоставить им доступ к классам Swift.

В качестве простого тестового проекта ObjectiveC-Test, Я создал класс:

// Quiz.swift

import Foundation 
import ClassKit 

@objcMembers public class Quiz : NSObject
{
    var mTitle            : String
    var mNumberOfProblems : Double
    var mNumberCorrect    : Double

    var context = CLSContext (type : CLSContextType.quiz, identifier : "Test", title : "Parent Test")

    override init ()
    {
        self.mTitle            = ""
        self.mNumberOfProblems = 0
        self.mNumberCorrect    = 0

        super.init()
    }


    init (title : String)
    {
        self.mTitle            = title
        self.mNumberOfProblems = 0
        self.mNumberCorrect    = 0
    }

}  // end class


protocol Node
{
    var parent      : Node?          { get }
    var children    : [Node]?        { get }
    var identifier  : String         { get }
    var contextType : CLSContextType { get }
}


extension Quiz : Node
{
    var parent      : Node?          { return nil }
    var children    : [Node]?        { return nil }
    var identifier  : String         { return mTitle }
    var contextType : CLSContextType { return .quiz }
}

«Узел протокола» и «Расширение Quiz: Node» взяты из проекта Apple GreatPlays, который иллюстрирует, как включить ClassKitв проекты, но это строго Swift код.CLSContext является классом ClassKit и не вызывает никаких проблем, но "CLSContextType", перечисление в ClassKit, вызывает и приводит к ошибке в заголовке ...- Swift.h: "Неизвестное имя типа 'CLSContextType'.

Однако в классе викторины "CLSContextType.quiz" в "var context = CLSContext (...)" не вызывает никаких проблем. Но если я добавлю строку "" var contextType = CLSContextType.quiz "в класс викториныЯ получаю сообщение об ошибке.

Соответствующий код в сгенерированном xcode заголовке быстрого моста (ObjectiveC_Test-Swift.h):

@class CLSContext;

SWIFT_CLASS("_TtC15ObjectiveC_Test4Quiz")
@interface Quiz : NSObject
@property (nonatomic, copy) NSString * _Nonnull mTitle;
@property (nonatomic) double mNumberOfProblems;
@property (nonatomic) double mNumberCorrect;
@property (nonatomic, strong) CLSContext * _Nonnull context;
- (nonnull instancetype)init OBJC_DESIGNATED_INITIALIZER;
- (nonnull instancetype)initWithTitle:(NSString * _Nonnull)title OBJC_DESIGNATED_INITIALIZER;
@end


@interface Quiz (SWIFT_EXTENSION(ObjectiveC_Test))
@property (nonatomic, readonly, copy) NSString * _Nonnull identifier;
@property (nonatomic, readonly) CLSContextType contextType;
@end

Ошибка возникает в следующей за последней строкой:"CLSContextType contextType": "Неизвестное имя типа 'CLSContextType'".Он также генерирует ошибку: «Тип интерфейса не может быть статически распределен», но я думаю, что это связано с первой ошибкой.«CLSContext» в восьмой строке не вызывает никаких ошибок.

Если я закомментирую строки CLSContextType в протоколе и в расширении узла, проект будет работать нормально.

Проект находится подxcode 10.0 и ios 11.4.

Настройки сборки включают в себя:

Packaging
   Defines Module:    Yes

Build Options
   Always Embed Swift Standard Libraries:  Yes

Swift Compiler - General:
   Install Objective-C Compatibility Header:  Yes
   Objective-C Bridging Header:   ObjectiveC-Test/ObjectiveC-Test-Bridging-Header.h
   Objective-C-Generated Interface Header Name:   ObjectiveC_Test-Swift.h

Apple Clang - Language - C++
   C++ Language Dialect:  GNU++14 [std=gnu++14]
   C++ Standard Library:  libcc++ (LLVM C++ standard library with C++11 support)

Любая помощь будет принята с благодарностью.

Обновление:

Удаление "@objcMembers"из класса Quiz устранена ошибка CLSContextType в заголовочном мосте, созданном xcode, но свойства класса больше не были доступны из файлов Objective-C ++ .mm.Добавление «@obj» к исправленным, но не работающим с contextType.

Доступ к свойствам класса и их печать в файле Objective-C ++ .mm.

Свойства протокола, включая CLSContextType, может быть напечатан в файле Objective-C ++ .mm из функции swift (начало) и функции расширения узла (printContextTypeFromNodeExtension).

//  @objcMembers public class Quiz : NSObject
public class Quiz : NSObject
{
    @objc var mTitle            : String
    @objc var mNumberOfProblems : Double
    @objc var mNumberCorrect    : Double
//    @objc var mLessonContextType : CLSContextType { return .lesson }  //  doesn't work
                                                           //  causes same bridging error


@objc func start ()
{
    print ("printing title from start() in swift: \(mTitle)")
    print ("printing identifier from start() in swift: \(identifier)")

    print ("printing CLSContextType from start() in swift: \(contextType.rawValue)")
    printContextTypeFromNodeExtension ()
}

}  // end class

extension Node
{
    func printContextTypeFromNodeExtension ()
    {
        print ("printing CLSContextType from Node extension: \(contextType.rawValue)")
    }    
}

Файл Objective-C ++ .mm:

Quiz * Q1 = [ [Quiz alloc] init];
Q1.mTitle = @"Place Value Blocks";
Q1.mNumberOfProblems = 10;
Q1.mNumberCorrect    = 3;

printf ("printing mTitle from objc: %s \n", [Q1.mTitle UTF8String] );
printf ("printing mNumberCorrect from objc: %f \n", Q1.mNumberCorrect);

[Q1 start];

Results:

printing mTitle from objc: Place Value Blocks 
printing mNumberCorrect from objc: 3.000000 

printing title from start() in swift: Place Value Blocks
printing identifier from start() in swift: Place Value Blocks
printing CLSContextType from start() in swift: 8
printing CLSContextType from Node extension: 8

Добавление "@objc" к протоколу Node позволило получить доступ ко всем свойствам Node в файлах Objective-C ++ .mm, кроме CLSContextType.Если его оставить, возвращается ошибка заголовка быстрого моста.

@objc protocol Node
{
    var parent      : Node?          { get }
    var children    : [Node]?        { get }
    var identifier  : String         { get }
    //  var contextType : CLSContextType { get }  // error if included when "@objc" added
}


extension Quiz : Node
{
    var parent      : Node?          { return nil }
    var children    : [Node]?        { return nil }
    var identifier  : String         { return mTitle }
//    var contextType : CLSContextType { return .quiz }
}

Objective-C++ .mm file:

printf ("printing parent from objc: %p \n", [Q1 parent] );
printf ("printing children from objc: %p \n", [Q1 children] );
printf ("printing identifier from objc: %s \n", [Q1.identifier UTF8String] );

Results:

printing parent from objc: 0x0 
printing children from objc: 0x0 
printing identifier from objc: Place Value Blocks 

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

1 Ответ

0 голосов
/ 22 января 2019

Импортирует ли ваш ObjC-заголовок ClassKit?

Протокол, он должен быть объявлен с помощью @ objc.

@objc protocol Node
...