Доступ к свойству протокола Swift, реализованному в классе Obj-C, из другого класса Swift - PullRequest
0 голосов
/ 23 января 2019

Я видел много вопросов относительно реализации протоколов Obj-C в Swift, но не так сильно наоборот, и я не видел этого специально.

Я использую смешанную кодовую базу Obj-C / Swift. У меня есть протокол Swift, определенный следующим образом:

NamedItem.swift

@objc protocol NamedItem {
    var name: String { get }
}

У меня есть класс Objective-C, который в настоящее время имеет собственное свойство name:

MyObjcClass.h

@interface MyObjcClass : NSObject
@property (nonatomic, strong, readonly) NSString* name;
@end

У меня есть пара других классов, обладающих свойством name, поэтому, очевидно, я бы хотел связать их всех с протоколом, а не типизировать с кучей разных типов. Теперь, если я попытаюсь переключить свой класс Obj-C со своего собственного свойства на реализацию протокола Swift:

MyObjcClass.h

@protocol MyObjcProtocol
@property (nonatomic, strong, readonly) NSString* place;
@end

@interface MyObjcClass : NSObject
@end

MyObjcClass.m

@interface MyObjcClass () <NamedItem>
@end

@implementation MyObjcClass
@synthesize name = _name;
@synthesize place = _place;
@end

Это прекрасно работает, в других моих классах Objective-C , но если я пытаюсь получить доступ к свойству name из класса Swift :

SomeSwiftClass.swift

let myObj = MyObjcClass()
myObj.name // error
myObj.place // no problem

Я получаю следующую ошибку:

Значение типа 'MyObjcClass' не имеет члена 'name'

Если я не удаляю существующую декларацию @property из MyObjcClass.h и опускаю инструкцию @synthesize, все создается правильно. Что кажется странным и неправильным - если вы принимаете протокол Objc-C из класса Obj-C, вам не нужно переопределять свойство, достаточно только оператора @synthesize.

Я пытался определить протокол Swift обо всех способах, о которых я мог придумать, и смог найти предложения, но я не смог обойти это.

Итак, как правильно реализовать свойство протокола Swift (может, в частности, свойство только для чтения?) В классе Objective-C, чтобы другой класс Swift мог получить к нему доступ? Должен ли я действительно повторно объявить свойство в заголовке Obj-C? Я знаю, что всегда мог отказаться от него и просто определить протокол в Objective-C, но ... Swift - это будущее! (или что-то в этом роде ...)

Ответы [ 2 ]

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

Хорошо, удалось получить рабочее решение с некоторыми предложениями от JoshCaswell и этого сообщения в блоге.

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

NamedItem.swift

@objc protocol NamedObject {
    var name: String { get }
}

MyObjcClass.h

@protocol NamedItem;

@interface MyObjcClass : NSObject
- (id<NamedItem>)asNamedItem;
@end

MyObjcClass.m

@interface MyObjcClass () <NamedItem>
@synthesize name = _name;

- (id<NamedItem>)asNamedItem
{
    return self;
}
@end

Использование теперь выглядит следующим образом:

SomeSwiftClass.swift

let myObj = MyObjcClass()
myObj.asNamedItem.name

Не так безобидно чисто, как хотелось бы, но лучше, чем кучапредупреждений или признания поражения и переписывания протокола в Objective-C.(Я не знаю, может быть, это не так ... но это то, с чем я пошел).

Надеюсь, это поможет кому-то еще.

0 голосов
/ 23 января 2019
// MyObjcClass.m

@interface MyObjcClass () <NamedItem>
@end

Это объявление не видно Swift. Переместите пункт соответствия протокола <NamedItem> в заголовочный файл класса.

// MyObjCClass.h

// Required for visibility of the protocol
#import "MyProject-Swift.h"

@interface MyObjcClass : NSObject <NamedItem>
@end

Как вы прокомментировали, компилятор Swift по-прежнему говорит, что myObj не имеет свойства name. Это довольно странно. Обратите внимание, что

let myObj = MyObjcClass() as NamedItem
myObj.name

отлично компилируется.

...