Расширение класса Swift с помощью категории Objective C
Im в ситуации, когда мне нужно использовать Objective C для расширения класса Swift. Я сделал что-то следующее:
В "SomeClass.swift":
class SomeClass: NSObject {
}
В "SomeClass + Extension.h":
#import "Project-Swift.h"
@interface SomeClass (Extension)
-(void)someMethod();
@end
Это сработало хорошо. И если я попытаюсь использовать расширение SomeClass в моем коде Objective C, это нормально.
Проблема в том, что если я хочу использовать someMethod()
в другом классе Swift, мне нужно будет поместить файл SomeClass+Extension.h
в мой файл ObjC-BridgingHeader.h
.
Но выполнение этого приведет к зависимости circuclar, потому что SomeClass+Extension.h
также импортирует Project-Swift.h
.
Есть ли у кого хороший способ обойти это?
Обратите внимание, что просто переадресация объявления класса в заголовке категории не будет работать, поскольку категории не могут использовать форвардные объявления для собственной реализации так:
@class SomeClass
без импорта Project-Swift.h
даст ошибку компиляции.
Ответы
Ответ 1
Плохой
Я тоже борюсь с этой проблемой. к сожалению, documentation довольно явно заявляет, что этот шаблон не разрешен:
Чтобы избежать циклических ссылок, не импортируйте код Swift в Objective-C заголовок (.h). Вместо этого вы можете переслать объявление Swift класс или протокол для ссылки на него в интерфейсе Objective-C.
Передовые декларации классов и протоколов Swift могут использоваться только как типы для объявлений методов и свойств.
также на всей связанной странице вы заметите, что он продолжает упоминать, чтобы импортировать сгенерированный заголовок специально в файл .m:
Чтобы импортировать код Swift в Objective-C из той же цели
Импортировать код Swift из этой цели в любой файл Objective-C.m внутри этой цели
Хороший
одним из решений, которое может работать для вас, является создание быстрого расширения, которое переопределяет каждый метод, который вам нужен в этой категории. это хрупкое и уродливое, но, возможно, самое чистое решение.
/**
Add category methods from objc here (since circular references prohibit the ObjC extension file)
*/
extension SomeClass {
@nonobjc func someMethod() {
self.performSelector(Selector("someMethod"))
}
}
- добавление
@noobjc
к фронту позволяет
та же сигнатура метода, которая будет использоваться без переопределения реализации ObjC
- теперь
import "SomeClass+Extension.h"
от моста
заголовок может быть удален
если требуется поддержка более двух входных параметров, или требуется более жесткая связь, я бы рекомендовал использовать среду выполнения для вызова базовой функции. отличное описание здесь.
Ответ 2
Как одно простое решение, вы можете переместить расширение на ваш код Swift. Тогда у вас не будет проблем с зависимостью.
Ответ 3
В Руководстве по совместимости мы не можем напрямую обращаться к объектам Objc подкласса/категоризации/расширения для класса .swift [SomeClass].
Но как поворот, мы можем это сделать:
Для переменных мы можем это сделать:
extension Class {
private struct AssociatedKeys {
static var DescriptiveName = "sh_DescriptiveName"
}
var descriptiveName: String? {
get {
return objc_getAssociatedObject(self, &AssociatedKeys.DescriptiveName) as? String
}
set {
if let newValue = newValue {
objc_setAssociatedObject(
self,
&AssociatedKeys.DescriptiveName,
newValue as NSString?,
.OBJC_ASSOCIATION_RETAIN_NONATOMIC
)
}
}
}
}
Для методов мы можем использовать метод_swizzling, который не рекомендуется.