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.
Partagez le code tout de suite. Il est publié sur GitHub avec une licence Apache-2.0.
https://github.com/zacky1972/swift_objc_test
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
Pour pouvoir appeler depuis Objective-C, effectuez les deux opérations suivantes.
import Foundation
pour dériver de NSObject
@ objc
à la classe et à la méthode que vous souhaitez appeler depuis Objective-C.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.
ExampleClass
, utilisez import" ExampleClass-Swift.h "
(Importez le fichier d'en-tête avec -Swift.h
ajouté au nom de la classe).Tout ce que vous avez à faire est de le lire comme Objective-C et de l'appeler normalement.
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.
swiftc
pour compiler Swift. Compilez dans un fichier objet (.o
) avec les options -emit-object
et -parse-as-library
.clang
pour compiler Objective-Cswiftc
et spécifiez -framework Foundation
comme option de liaison.ExampleClass-Swift.h
(fichier d'en-tête donné à Objective-C), utilisez swiftc
et l'option -emit-objc-header
. Et utilisez l'option -emit-objc-header-path
. Spécifiez le chemin d'accès au fichier d'en-tête que vous souhaitez générer immédiatement après l'option -emit-objc-header-path
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
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!
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