Comment appeler le code Swift 5.3 depuis Objective-C

Le premier Apple Silicon Mac avec la puce M1 est enfin là. On a l'impression que les avantages et les inconvénients tourbillonnent sur le net.

Je suis actuellement un utilisateur Mac, mais plutôt que de remplacer mon Mac, je regarde son application potentielle au projet de satellite artificiel sur lequel je travaille. Je m'attends à ce que les performances de traitement d'image par prix du nouveau Mac soient extrêmement élevées et que les performances de traitement d'image par consommation d'énergie soient également bonnes. J'écrirai sur le projet de satellite artificiel dans Elixir Advent Calendar 2020, alors attendez-le avec impatience.

Ainsi, au lieu de développer des applications iOS et des applications Mac, en utilisant le mécanisme pour appeler le programme C appelé NIF d'Elixir, appelez les actifs de code de Swift accumulés par Apple tels que Core Image et Core ML d'Elixir. J'ai écrit cet article dans le but de voir si je pouvais le faire. Si vous pouvez appeler Swift depuis Objective-C, vous pouvez appeler Objective-C depuis C, vous pouvez donc également appeler Swift depuis Elixir.

En ce qui concerne Swift, à l'exception du programme Apple Developer Program, il n'y avait que des articles avec des spécifications d'ancienne langue, donc cet article correspondant à Swift 5.3 adopté dans Xcode 12.1, qui est le dernier Xcode en date du 12.11.2020, est similaire. Je pense qu'il y a quelque chose de nouveau dans l'article.

J'utilise également make sur la ligne de commande au lieu de Xcode pour compiler le code Swift / Objective-C. Je pense que la façon d'écrire «Makefile» est également utile.

Le code fini

Partagez le code tout de suite. Il est publié sur GitHub avec une licence Apache-2.0.

https://github.com/zacky1972/swift_objc_test

Code SWIFT (appelé)

Le code Swift que je souhaite appeler est:

ExampleClass.swift


import Foundation

@objc class ExampleClass: NSObject {
	var count = 0
	@objc func increment() {
		count += 1
		NSLog("increment")
	}
	@objc func increment(by amount: Int) {
		count += amount
	}
	@objc func reset() {
		count = 0
	}
}

La source de ce code est ici. https://docs.swift.org/swift-book/LanguageGuide/Methods.html

Code Objective-C (appelant)

Pour pouvoir appeler depuis Objective-C, effectuez les deux opérations suivantes.

Le code du côté Objective-C ressemble à ceci.

main.m


#import <Foundation/Foundation.h>
#import "ExampleClass-Swift.h"

int main(int argc, char** argv)
{
	ExampleClass *obj = [[ExampleClass alloc] init];
	[obj increment];
	NSLog(@"Testing");
}

Les points sont les suivants.

Tout ce que vous avez à faire est de le lire comme Objective-C et de l'appeler normalement.

Résultat d'exécution

Le résultat de l'exécution est le suivant.

% ./hello 
2020-11-12 18:47:57.204 hello[10554:225821] increment
2020-11-12 18:47:57.204 hello[10554:225821] Testing

Comme prévu, puisque la méthode increment a été appelée plus tôt, elle dit Testing.

C'est tout le code à préparer.

Makefile

Jetons un œil au Makefile pour voir comment le construire.

Makefile


.phony: all clean

all: hello


main.o: main.m ExampleClass-Swift.h
	clang -c $< -o $@

ExampleClass.o: ExampleClass.swift ExampleClass-Swift.h
	swiftc -emit-object -parse-as-library $<

ExampleClass-Swift.h: ExampleClass.swift
	swiftc $< -emit-objc-header -emit-objc-header-path $@

hello: main.o ExampleClass.o
	swiftc $^ -o $@ -framework Foundation

clean:
	$(RM) hello *.o *.{swiftdoc,swiftmodule,swiftsourceinfo} ExampleClass ExampleClass-Swift.h

Les points sont les suivants.

Fichier d'en-tête Objective-C généré

Le fichier d'en-tête Objective-C généré est:

ExampleClass-Swift.h


// Generated by Apple Swift version 5.3 (swiftlang-1200.0.29.2 clang-1200.0.30.1)
#ifndef EXAMPLECLASS_SWIFT_H
#define EXAMPLECLASS_SWIFT_H
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wgcc-compat"

#if !defined(__has_include)
# define __has_include(x) 0
#endif
#if !defined(__has_attribute)
# define __has_attribute(x) 0
#endif
#if !defined(__has_feature)
# define __has_feature(x) 0
#endif
#if !defined(__has_warning)
# define __has_warning(x) 0
#endif

#if __has_include(<swift/objc-prologue.h>)
# include <swift/objc-prologue.h>
#endif

#pragma clang diagnostic ignored "-Wauto-import"
#include <Foundation/Foundation.h>
#include <stdint.h>
#include <stddef.h>
#include <stdbool.h>

#if !defined(SWIFT_TYPEDEFS)
# define SWIFT_TYPEDEFS 1
# if __has_include(<uchar.h>)
#  include <uchar.h>
# elif !defined(__cplusplus)
typedef uint_least16_t char16_t;
typedef uint_least32_t char32_t;
# endif
typedef float swift_float2  __attribute__((__ext_vector_type__(2)));
typedef float swift_float3  __attribute__((__ext_vector_type__(3)));
typedef float swift_float4  __attribute__((__ext_vector_type__(4)));
typedef double swift_double2  __attribute__((__ext_vector_type__(2)));
typedef double swift_double3  __attribute__((__ext_vector_type__(3)));
typedef double swift_double4  __attribute__((__ext_vector_type__(4)));
typedef int swift_int2  __attribute__((__ext_vector_type__(2)));
typedef int swift_int3  __attribute__((__ext_vector_type__(3)));
typedef int swift_int4  __attribute__((__ext_vector_type__(4)));
typedef unsigned int swift_uint2  __attribute__((__ext_vector_type__(2)));
typedef unsigned int swift_uint3  __attribute__((__ext_vector_type__(3)));
typedef unsigned int swift_uint4  __attribute__((__ext_vector_type__(4)));
#endif

#if !defined(SWIFT_PASTE)
# define SWIFT_PASTE_HELPER(x, y) x##y
# define SWIFT_PASTE(x, y) SWIFT_PASTE_HELPER(x, y)
#endif
#if !defined(SWIFT_METATYPE)
# define SWIFT_METATYPE(X) Class
#endif
#if !defined(SWIFT_CLASS_PROPERTY)
# if __has_feature(objc_class_property)
#  define SWIFT_CLASS_PROPERTY(...) __VA_ARGS__
# else
#  define SWIFT_CLASS_PROPERTY(...)
# endif
#endif

#if __has_attribute(objc_runtime_name)
# define SWIFT_RUNTIME_NAME(X) __attribute__((objc_runtime_name(X)))
#else
# define SWIFT_RUNTIME_NAME(X)
#endif
#if __has_attribute(swift_name)
# define SWIFT_COMPILE_NAME(X) __attribute__((swift_name(X)))
#else
# define SWIFT_COMPILE_NAME(X)
#endif
#if __has_attribute(objc_method_family)
# define SWIFT_METHOD_FAMILY(X) __attribute__((objc_method_family(X)))
#else
# define SWIFT_METHOD_FAMILY(X)
#endif
#if __has_attribute(noescape)
# define SWIFT_NOESCAPE __attribute__((noescape))
#else
# define SWIFT_NOESCAPE
#endif
#if __has_attribute(ns_consumed)
# define SWIFT_RELEASES_ARGUMENT __attribute__((ns_consumed))
#else
# define SWIFT_RELEASES_ARGUMENT
#endif
#if __has_attribute(warn_unused_result)
# define SWIFT_WARN_UNUSED_RESULT __attribute__((warn_unused_result))
#else
# define SWIFT_WARN_UNUSED_RESULT
#endif
#if __has_attribute(noreturn)
# define SWIFT_NORETURN __attribute__((noreturn))
#else
# define SWIFT_NORETURN
#endif
#if !defined(SWIFT_CLASS_EXTRA)
# define SWIFT_CLASS_EXTRA
#endif
#if !defined(SWIFT_PROTOCOL_EXTRA)
# define SWIFT_PROTOCOL_EXTRA
#endif
#if !defined(SWIFT_ENUM_EXTRA)
# define SWIFT_ENUM_EXTRA
#endif
#if !defined(SWIFT_CLASS)
# if __has_attribute(objc_subclassing_restricted)
#  define SWIFT_CLASS(SWIFT_NAME) SWIFT_RUNTIME_NAME(SWIFT_NAME) __attribute__((objc_subclassing_restricted)) SWIFT_CLASS_EXTRA
#  define SWIFT_CLASS_NAMED(SWIFT_NAME) __attribute__((objc_subclassing_restricted)) SWIFT_COMPILE_NAME(SWIFT_NAME) SWIFT_CLASS_EXTRA
# else
#  define SWIFT_CLASS(SWIFT_NAME) SWIFT_RUNTIME_NAME(SWIFT_NAME) SWIFT_CLASS_EXTRA
#  define SWIFT_CLASS_NAMED(SWIFT_NAME) SWIFT_COMPILE_NAME(SWIFT_NAME) SWIFT_CLASS_EXTRA
# endif
#endif
#if !defined(SWIFT_RESILIENT_CLASS)
# if __has_attribute(objc_class_stub)
#  define SWIFT_RESILIENT_CLASS(SWIFT_NAME) SWIFT_CLASS(SWIFT_NAME) __attribute__((objc_class_stub))
#  define SWIFT_RESILIENT_CLASS_NAMED(SWIFT_NAME) __attribute__((objc_class_stub)) SWIFT_CLASS_NAMED(SWIFT_NAME)
# else
#  define SWIFT_RESILIENT_CLASS(SWIFT_NAME) SWIFT_CLASS(SWIFT_NAME)
#  define SWIFT_RESILIENT_CLASS_NAMED(SWIFT_NAME) SWIFT_CLASS_NAMED(SWIFT_NAME)
# endif
#endif

#if !defined(SWIFT_PROTOCOL)
# define SWIFT_PROTOCOL(SWIFT_NAME) SWIFT_RUNTIME_NAME(SWIFT_NAME) SWIFT_PROTOCOL_EXTRA
# define SWIFT_PROTOCOL_NAMED(SWIFT_NAME) SWIFT_COMPILE_NAME(SWIFT_NAME) SWIFT_PROTOCOL_EXTRA
#endif

#if !defined(SWIFT_EXTENSION)
# define SWIFT_EXTENSION(M) SWIFT_PASTE(M##_Swift_, __LINE__)
#endif

#if !defined(OBJC_DESIGNATED_INITIALIZER)
# if __has_attribute(objc_designated_initializer)
#  define OBJC_DESIGNATED_INITIALIZER __attribute__((objc_designated_initializer))
# else
#  define OBJC_DESIGNATED_INITIALIZER
# endif
#endif
#if !defined(SWIFT_ENUM_ATTR)
# if defined(__has_attribute) && __has_attribute(enum_extensibility)
#  define SWIFT_ENUM_ATTR(_extensibility) __attribute__((enum_extensibility(_extensibility)))
# else
#  define SWIFT_ENUM_ATTR(_extensibility)
# endif
#endif
#if !defined(SWIFT_ENUM)
# define SWIFT_ENUM(_type, _name, _extensibility) enum _name : _type _name; enum SWIFT_ENUM_ATTR(_extensibility) SWIFT_ENUM_EXTRA _name : _type
# if __has_feature(generalized_swift_name)
#  define SWIFT_ENUM_NAMED(_type, _name, SWIFT_NAME, _extensibility) enum _name : _type _name SWIFT_COMPILE_NAME(SWIFT_NAME); enum SWIFT_COMPILE_NAME(SWIFT_NAME) SWIFT_ENUM_ATTR(_extensibility) SWIFT_ENUM_EXTRA _name : _type
# else
#  define SWIFT_ENUM_NAMED(_type, _name, SWIFT_NAME, _extensibility) SWIFT_ENUM(_type, _name, _extensibility)
# endif
#endif
#if !defined(SWIFT_UNAVAILABLE)
# define SWIFT_UNAVAILABLE __attribute__((unavailable))
#endif
#if !defined(SWIFT_UNAVAILABLE_MSG)
# define SWIFT_UNAVAILABLE_MSG(msg) __attribute__((unavailable(msg)))
#endif
#if !defined(SWIFT_AVAILABILITY)
# define SWIFT_AVAILABILITY(plat, ...) __attribute__((availability(plat, __VA_ARGS__)))
#endif
#if !defined(SWIFT_WEAK_IMPORT)
# define SWIFT_WEAK_IMPORT __attribute__((weak_import))
#endif
#if !defined(SWIFT_DEPRECATED)
# define SWIFT_DEPRECATED __attribute__((deprecated))
#endif
#if !defined(SWIFT_DEPRECATED_MSG)
# define SWIFT_DEPRECATED_MSG(...) __attribute__((deprecated(__VA_ARGS__)))
#endif
#if __has_feature(attribute_diagnose_if_objc)
# define SWIFT_DEPRECATED_OBJC(Msg) __attribute__((diagnose_if(1, Msg, "warning")))
#else
# define SWIFT_DEPRECATED_OBJC(Msg) SWIFT_DEPRECATED_MSG(Msg)
#endif
#if !defined(IBSegueAction)
# define IBSegueAction
#endif
#if __has_feature(modules)
#if __has_warning("-Watimport-in-framework-header")
#pragma clang diagnostic ignored "-Watimport-in-framework-header"
#endif
@import ObjectiveC;
#endif

#pragma clang diagnostic ignored "-Wproperty-attribute-mismatch"
#pragma clang diagnostic ignored "-Wduplicate-method-arg"
#if __has_warning("-Wpragma-clang-attribute")
# pragma clang diagnostic ignored "-Wpragma-clang-attribute"
#endif
#pragma clang diagnostic ignored "-Wunknown-pragmas"
#pragma clang diagnostic ignored "-Wnullability"

#if __has_attribute(external_source_symbol)
# pragma push_macro("any")
# undef any
# pragma clang attribute push(__attribute__((external_source_symbol(language="Swift", defined_in="ExampleClass",generated_declaration))), apply_to=any(function,enum,objc_interface,objc_category,objc_protocol))
# pragma pop_macro("any")
#endif


SWIFT_CLASS("_TtC12ExampleClass12ExampleClass")
@interface ExampleClass : NSObject
- (void)increment;
- (void)incrementBy:(NSInteger)amount;
- (void)reset;
- (nonnull instancetype)init OBJC_DESIGNATED_INITIALIZER;
@end

#if __has_attribute(external_source_symbol)
# pragma clang attribute pop
#endif
#pragma clang diagnostic pop
#endif

Sommaire

Cette découverte permet d'appeler du code Swift 5.3 à partir d'Objective-C. En écrivant un code séparé qui appelle Objective-C depuis C, vous pouvez appeler Swift depuis C. En d'autres termes, vous pouvez appeler librement l'API Swift et Apple d'Elixir. Banzai!

Merci

Ce résultat de recherche a été soutenu par A-STEP Tryout JPMJTM20H1 qui est un programme de soutien pour le développement optimal des résultats de recherche dans le projet de développement des résultats de recherche de l'Agence japonaise pour la science et la technologie.

Recommended Posts

Comment appeler le code Swift 5.3 depuis Objective-C
Comment appeler AmazonSQSAsync
Comment implémenter UICollectionView avec du code uniquement dans Swift
Comment écrire du bon code
[Code de test d'intégration] Comment sélectionner un élément dans date_select
Comment appliquer le format de code C à partir de la ligne de commande
Comment appeler des classes et des méthodes
[Swift] Comment envoyer une notification
Passer d'Eclipse à VS Code
Comment rédiger un code facile à comprendre [Résumé 3]
[Swift] Comment remplacer plusieurs chaînes
Appeler les fonctions du langage C depuis Swift
Comment passer du HTML à Haml
Comment ouvrir un fichier de script à partir d'Ubuntu avec du code VS
[Swift5] Comment communiquer de ViewController à Model et transmettre une valeur
[swift5] Comment spécifier la couleur en hexadécimal
[Rails] Comment convertir ERB en Haml
[Flutter] Comment utiliser C / C ++ depuis Dart?
Java: Comment envoyer des valeurs du servlet au servlet
[Java] Flux du code source à l'exécution
[Swift5] Comment créer un écran de démarrage
[Swift5] Comment mettre en œuvre une animation à l'aide de "lottie-ios"
Comment écraser les données Firebase avec Swift
Comment compter rapidement les points de code UTF-8
Comment renvoyer une valeur du modèle au contrôleur en utilisant le protocole [Swift5]
[Swift] Résumé de la suppression des éléments d'un tableau (mémo personnel)
Comment appeler des services personnalisés / services standard à partir de Liferay 7 / DXP- Workflow / Workflow Script
[swift5] Comment changer la couleur de TabBar ou la couleur de l'élément de TabBar avec le code
Conversion du pointeur de chaîne de langage C en type Swift String
Comment lier Rails6 Vue (à partir de la construction de l'environnement)
Comment obtenir un heapdump à partir d'un conteneur Docker
Comment vider de la base de données (DB) vers le fichier de départ
Remarquez comment utiliser Swift Super Basic TableView
Comment obtenir une classe depuis Element en Java
Comment écrire du code qui pense Ruby orienté objet
[Swift UI] Comment désactiver ScrollsToTop de ScrollView
[Java] Comment passer de jdk ouvert à jdk oracle