Поиск…


замечания

Для получения дополнительной информации см. Документацию Apple по использованию Swift с Cocoa и Objective-C .

Использование классов Swift из кода Objective-C

В том же модуле

Внутри модуля с именем « MyModule » Xcode генерирует заголовок с именем MyModule-Swift.h который предоставляет общедоступные классы Swift для Objective-C. Импортируйте этот заголовок, чтобы использовать классы Swift:

// MySwiftClass.swift in MyApp
import Foundation

// The class must be `public` to be visible, unless this target also has a bridging header
public class MySwiftClass: NSObject {
    // ...
}
// MyViewController.m in MyApp

#import "MyViewController.h"
#import "MyApp-Swift.h"                    // import the generated interface
#import <MyFramework/MyFramework-Swift.h>  // or use angle brackets for a framework target

@implementation MyViewController
- (void)demo {
    [[MySwiftClass alloc] init];  // use the Swift class
}
@end

Соответствующие настройки сборки:

  • Objective-C Generated Interface Header Name : управляет именем сгенерированного заголовка Obj-C.
  • Установите заголовок совместимости Objective-C : должен ли заголовок -Swift.h быть общедоступным заголовком (для целей инфраструктуры).

скриншот настройки сборки


В другом модуле

Использование @import MyFramework; импортирует весь модуль, включая интерфейсы Obj-C, к классам Swift (если указан вышеупомянутый параметр сборки).

Использование классов Objective-C из кода Swift

Если MyFramework содержит классы Objective-C в своих публичных заголовках (и заголовок зонтика), тогда import MyFramework - это все, что необходимо для их использования из Swift.

Мостовые заголовки

Мостовой заголовок делает дополнительные объявления Objective-C и C видимыми для кода Swift. При добавлении файлов проекта Xcode может предлагать автоматически создавать заголовок моста:

диалог связывания заголовков

Чтобы создать его вручную, измените настройку сборки заголовка Objective-C Bridging Header :

введите описание изображения здесь

Внутри соединительного заголовка импортируйте файлы, которые необходимо использовать из кода:

// MyApp-Bridging-Header.h
#import "MyClass.h"  // allows code in this module to use MyClass

Сгенерированный интерфейс

Нажмите кнопку Связанные элементы (или нажмите ^ 1), затем выберите « Сгенерированный интерфейс», чтобы увидеть интерфейс Swift, который будет создан из заголовка Objective-C.

Укажите мостиковый заголовок для swiftc

-import-objc-header указывает заголовок для импорта swiftc :

// defs.h
struct Color {
    int red, green, blue;
};

#define MAX_VALUE 255
// demo.swift
extension Color: CustomStringConvertible {  // extension on a C struct
    public var description: String {
        return "Color(red: \(red), green: \(green), blue: \(blue))"
    }
}
print("MAX_VALUE is: \(MAX_VALUE)")  // C macro becomes a constant
let color = Color(red: 0xCA, green: 0xCA, blue: 0xD0)  // C struct initializer
print("The color is \(color)")
$ swiftc demo.swift -import-objc-header defs.h && ./demo
MAX_VALUE is: 255
The color is Color(red: 202, green: 202, blue: 208)

Используйте карту модуля для импорта заголовков C

Карта модуля может просто import mymodule , настроив его на чтение файлов заголовков C и превращая их в функции Swift.

Поместите файл с именем module.modulemap в каталог с именем mymodule :

структура каталогов

Внутри файла карты модуля:

// mymodule/module.modulemap
module mymodule {
    header "defs.h"
}

Затем import модуль:

// demo.swift
import mymodule
print("Empty color: \(Color())")

Используйте флаг -I directory чтобы сообщить swiftc где найти модуль:

swiftc -I . demo.swift   # "-I ." means "search for modules in the current directory"

Дополнительные сведения о синтаксисе карты модуля см. В документации Clang о картах модулей .

Мелкозернистая взаимосвязь между Objective-C и Swift

Когда API помечается NS_REFINED_FOR_SWIFT , при импорте в Swift он будет иметь префикс с двумя NS_REFINED_FOR_SWIFT подчеркивания ( __ ):

@interface MyClass : NSObject
- (NSInteger)indexOfObject:(id)obj NS_REFINED_FOR_SWIFT;
@end

Сгенерированный интерфейс выглядит следующим образом:

public class MyClass : NSObject {
    public func __indexOfObject(obj: AnyObject) -> Int
}

Теперь вы можете заменить API на более «Swifty» расширение. В этом случае мы можем использовать необязательное возвращаемое значение, отфильтровывая NSNotFound :

extension MyClass {
    // Rather than returning NSNotFound if the object doesn't exist,
    // this "refined" API returns nil.
    func indexOfObject(obj: AnyObject) -> Int? {
        let idx = __indexOfObject(obj)
        if idx == NSNotFound { return nil }
        return idx
    }
}

// Swift code, using "if let" as it should be:
let myobj = MyClass()
if let idx = myobj.indexOfObject(something) {
    // do something with idx
}

В большинстве случаев вы можете ограничить, может ли аргумент функции Objective-C быть nil . Это делается с использованием _Nonnull слова _Nonnull , которое квалифицирует любую ссылку указателя или блока:

void
doStuff(const void *const _Nonnull data, void (^_Nonnull completion)())
{
    // complex asynchronous code
}

С учетом этого компилятор должен испускать ошибку всякий раз, когда мы пытаемся передать nil этой функции из нашего кода Swift:

doStuff(
    nil,  // error: nil is not compatible with expected argument type 'UnsafeRawPointer'
    nil)  // error: nil is not compatible with expected argument type '() -> Void'

Противоположность _Nonnull _Nullable , что означает, что допустимо пропускать nil в этом аргументе. _Nullable также является значением по умолчанию; однако указание этого явно позволяет использовать более самодокументированный и будущий код.

Чтобы еще больше помочь компилятору с оптимизацией кода, вы также можете указать, будет ли блок экранироваться:

void
callNow(__attribute__((noescape)) void (^_Nonnull f)())
{
    // f is not stored anywhere
}

С помощью этого атрибута мы обещаем не сохранять ссылку на блок, а не вызывать блок после завершения функции.

Используйте стандартную библиотеку C

Совместимость Swift C позволяет использовать функции и типы из стандартной библиотеки C.

В Linux стандартная библиотека C отображается через модуль Glibc ; на платформах Apple это называется Darwin .

#if os(macOS) || os(iOS) || os(tvOS) || os(watchOS)
import Darwin
#elseif os(Linux)
import Glibc
#endif

// use open(), read(), and other libc features


Modified text is an extract of the original Stack Overflow Documentation
Лицензировано согласно CC BY-SA 3.0
Не связан с Stack Overflow