He visto muchas preguntas sobre la implementación de protocolos Obj-C en Swift, pero no tanto al revés, y no he visto esto específicamente.
Estoy usando una base de código mixta Obj-C / Swift. Tengo un protocolo Swift definido de la siguiente manera:
NamedItem.swift
@objc protocol NamedItem { var name: String { get } } Tengo una clase Objective-C existente que actualmente tiene su propia propiedad de name :
MiObjcClass.h
@interface MyObjcClass : NSObject @property (nonatomic, strong, readonly) NSString* name; @end Tengo un par de otras clases que tienen una propiedad de name , por lo que obviamente me gustaría asociarlas todas con un protocolo en lugar de encasillarlas en un montón de tipos diferentes. Ahora, si trato de cambiar mi clase Obj-C de tener su propia propiedad a implementar el protocolo Swift:
MiObjcClass.h
@protocol MyObjcProtocol @property (nonatomic, strong, readonly) NSString* place; @end @interface MyObjcClass : NSObject @endMiObjcClase.m
@interface MyObjcClass () <NamedItem> @end @implementation MyObjcClass @synthesize name = _name; @synthesize place = _place; @endEsto funciona muy bien, en mis otras clases de Objective-C , pero si trato de acceder a la propiedad de nombre desde una clase de Swift :
SomeSwiftClass.swift
let myObj = MyObjcClass() myObj.name // error myObj.place // no problemObtuve el siguiente error:
El valor de tipo 'MyObjcClass' no tiene 'nombre' de miembro
Si no elimino la declaración @property existente de MyObjcClass.h y omito la declaración @synthesize , todo se construye correctamente. Lo que parece extraño e incorrecto: si adopta un protocolo Objc-C de una clase Obj-C, no tiene que volver a definir la propiedad, solo la declaración @synthesize es suficiente.
Intenté definir el protocolo Swift de todas las formas que se me ocurrieron y pude encontrar sugerencias al respecto, pero no pude solucionar esto.
Entonces, ¿cuál es la forma correcta de implementar una propiedad de protocolo Swift (¿quizás específicamente una propiedad de solo lectura?) en una clase Objective-C de modo que otra clase Swift pueda acceder a ella? ¿ Realmente tengo que volver a declarar la propiedad en el encabezado Obj-C? Sé que siempre podría dejarlo y simplemente definir el protocolo en Objective-C, pero... ¡Swift es el futuro! (o algo así...)
// MyObjcClass.m @interface MyObjcClass () <NamedItem> @end Esta declaración no es visible para Swift. Mueva la cláusula de conformidad con el protocolo <NamedItem> al archivo de encabezado de la clase.
// MyObjCClass.h // Required for visibility of the protocol #import "MyProject-Swift.h" @interface MyObjcClass : NSObject <NamedItem> @end Como comentaste, el compilador de Swift todavía dice que myObj no tiene un name de propiedad. Esto es bastante extraño. Tenga en cuenta que
let myObj = MyObjcClass() as NamedItem myObj.namecompila bien.
Ok, logré obtener una solución funcional con algunas sugerencias de JoshCaswell y esta publicación de blog.
Las clases ahora se ven de la siguiente manera:
NamedItem.swift
@objc protocol NamedObject { var name: String { get } }MiObjcClass.h
@protocol NamedItem; @interface MyObjcClass : NSObject - (id<NamedItem>)asNamedItem; @endMiObjcClase.m
@interface MyObjcClass () <NamedItem> @synthesize name = _name; - (id<NamedItem>)asNamedItem { return self; } @endEl uso ahora se ve así:
SomeSwiftClass.swift
let myObj = MyObjcClass() myObj.asNamedItem.nameNo tan limpio como me gustaría, pero es mejor que un montón de advertencias o admitir la derrota y volver a escribir el protocolo en Objective-C. (No sé, tal vez no lo sea... pero es lo que hice).
Espero que eso ayude a alguien más.