Может ли код objective-c вызывать быстрое расширение для класса?

94

Я искал несколько сообщений, думаю, я не могу написать расширение под swift и вызвать его из кода Objective-C, верно?

@objc подобные атрибуты поддерживают только методы, класс, протоколы?

Sprhawk
источник
1
Почему бы тебе просто не попробовать?
ИМЕЕТ
7
ide пожаловался на ошибку, но я хочу получить определенный ответ.
sprhawk

Ответы:

84

Вы можете написать расширение Swift и использовать его в коде Objective-C. Протестировано с XCode 6.1.1.

Все, что вам нужно сделать, это:

  • создайте свое расширение в Swift (без @objcаннотации)

  • #import "ProjectTarget-Swift.h" в вашем классе Objective-C (где "ProjectTarget" представляет цель XCode, с которой связано расширение Swift)

  • вызывать методы из расширения Swift

Обновление: как упоминал @Rizwan Ahmed, вам необходимо добавить @objcаннотацию:

Начиная с Swift 4.0.3, аннотация @objc необходима, если вы хотите использовать расширение в файлах классов Objective C.

Мариус Бардан
источник
6
Я сделал именно это, но это все еще ошибка времени компиляции. Хммм. РЕДАКТИРОВАТЬ: я импортировал свой заголовок моста вместо «ProjectTarget-Swift.h». Der.
Джейсон Ренальдо,
Оба являются заголовками-мостами. Разница в том, что один предназначен для использования кода Swift в ObjC, а другой - для использования кода ObjC в Swift. Заголовок Swift невидим. Другой должен управляться вами.
мариус бардан
Уильям Ху, см. Ответ Маклафлина!
Appleitung
39
Начиная с Swift 4.0.3, аннотация @objc необходима, если вы хотите использовать расширение в файлах классов Objective C.
Ризван Ахмед
69

Я узнал, что в Swift 4.0 я должен был добавить @objcперед моим расширением ключевого слова для того , чтобы методы расширения Swift , чтобы стать видимым экземпляром класса ObjC я простирающимся.

Коротко:

Настройка файла конфигурации:

CustomClass.h
CustomClass.m
CustomClassExtension.swift

В CustomClassExtension:

@objc extension CustomClass
{
    func method1() 
    {
        ...
    }
}

В моем AppDelegate.m:

self.customClass = [[CustomClass alloc] init];
[self.customClass method1];
Андрей П.
источник
2
Если метод использует универсальные шаблоны, он не может использоваться Objective-C, и вам нужно будет добавить @nonobjcаннотацию.
ThomasW 01
Замечание: @objcMembers в этом случае не работает. Не знаю , почему .. :-(
Raunak
46

Это решение работает для Swift 2.2 и Swift 3 . Обратите внимание, что из Objective-C будут доступны только расширения для классов (не для структур или перечислений).

import UIKit

extension UIColor {

    //Custom colours
    class func otherEventColor() -> UIColor {
        return UIColor(red:0.525, green:0.49, blue:0.929, alpha:1)
    }
}

Затем #import "ProductModuleName-Swift.h" в файл ObjC.

Swift 4

extension UIColor {

    // As of Swift 4.0.3, the @objc annotation is needed if you want to use the extension in Objective-C files
    @objc
    class func otherEventColor() -> UIColor {
        return UIColor(red:0.525, green:0.49, blue:0.929, alpha:1)
    }
}
Фоти Дим
источник
Это не «YourProjectsNameHere ...», а скорее «YourTargetsNameHere ...»: чтобы делиться целями, вы должны заблокировать их для имени: dr2050.postach.io/post/…
Дэн Розенстарк
1
@DanRosenstark Вы правы. Я меняю его на «ProductModuleName-Swift.h», как предлагает Apple: developer.apple.com/library/ios/documentation/Swift/Conceptual/…
Фоти Дим
1
Отлично работает для Swift 3.
Виктор Кучера
Есть ли причина, по которой вы говорите, что publicэто необходимо? У publicменя отлично работает без модификатора. Предполагаем ли мы, что расширение находится не в том же проекте, а импортируется из другого проекта?
Ли Кан,
Нужно ли использовать мостовой заголовок?
jegadeesh 06
42

Как описано в других ответах, в большинстве случаев работает импорт сгенерированного заголовка Swift .

Исключение составляют случаи, когда категория определена в мостовом типе (т.е. расширение определено в типе, Stringа не в нем NSString). Эти категории не будут автоматически связаны с их аналогами в Objective-C. Чтобы обойти это, вам нужно либо использовать тип Objective-C (и привести возвращаемое значение в код Swift с помощью as String), либо определить расширение для типов Swift и Objective-C.

Маклафлиндж
источник
2
Добавляя к ответу выше, вы должны сделать свое быстрое расширение общедоступным и установить его тип как NSString, например public extension NSString. Если вы получите неразрешенный идентификатор или аналогичную ошибку во время компиляции, вы можете снова выполнить приведение обратно к String, например, let sVal = self as Stringа затем вызвать необходимый кодsVal
RunLoop
@RunLoop на самом деле вам не нужен public, он будет работать без спецификатора области. И это (экспорт в Obj-C, я имею в виду) не работает для строк, потому что они являются структурами, а не классами и доступны только из Swift. Итак, да - вы можете написать расширение для NSString и использовать приведение или написать расширения, как mclaughlinjсказано, как для класса NSString, так и для структуры String
Алекс Назарский 02
3

Импортируйте заголовок "#import" ProductModuleName-Swift.h в файл objective-c и добавьте @objc перед своим расширением в файл swift. Он будет нормально работать в swift 4.2 и swift 5.

Ранджани
источник
0

Если вы считаете, что все настроили правильно (пометили свои Swift-объекты с помощью @objcMembers или @objc, импортировали заголовок моста "ProductModuleName-Swift.h" и т. Д.) - но все равно получаете сообщение об No visible @interface for 'FooClass' declares the selector 'fooSelector'ошибке:

Убедитесь, что вы видите свои интерфейсы в заголовке моста , ctrl + cmdщелкнув по нему. Если нет, ознакомьтесь с моим ответом на этот вопрос: заголовок Swift to Objective-C не содержит классов Swift.

Тайсак
источник