(反射)在Swift中通过函数名称调用带有参数的方法

本雅姆·埃弗雷姆(Benyam Ephrem)

语境

我有一个名为的类的实例,Solution并且我有一个函数名称作为functionName要在该Solution实例上调用的字符串solutionInstance我在数组中有函数的参数,我也想传递这些参数。

我正在使用Swift编译器将我的所有.swift文件(swiftc一起枚举的文件,然后-o是输出文件名)一起编译,然后运行最终输出。

Python范例

这是我在Python中执行的操作:

method = getattr(solutionInstance, functionName) # get method off of instance for function
programOutput = method(*testInputsParsed) # pass the list of parameters & call the method

目的

这是在容器中运行的服务器端代码,用于运行用户的代码。此代码位于“驱动程序”main.swift文件中,该文件调用方法并编排测试。

问题

Swift是静态类型的,我一直在搜索,大多数资料都说Swift中对反射的支持有限(并建议“深入到Objective-C”以获得所需的功能)。

Swift不是我的母语(TypeScript / JavaScript,Java,Python最强,然后是C#和C ++,然后才实现此功能的Swift代码),所以我不确定这意味着什么,所以我一直找不到明确的答案。

如何在Solution类实例上通过函数名称调用函数(至少我没有实现任何协议),并在Swift中传递参数数组(使用反射)?如何更改我的设置以实现此目的(导入库等)

谢谢!

参考文章
blld

首先,正如您所指出的,Swift没有完整的反射功能,并且依赖于共存的ObjC提供这些功能。

因此,即使您可以编写纯Swift代码,也需要Solution成为NSObject(或实现NSObjectProtocol的子类

游乐场样本:

class Solution: NSObject {

    @objc func functionName(greeting: String, name: String) {
        print(greeting, name)
    }

}

let solutionInstance = Solution() as NSObject
let selector = #selector(Solution.functionName)
if solutionInstance.responds(to: selector) {
    solutionInstance.perform(selector, with: "Hello", with: "solution")
}

这里还有其他关注点:

  • Swiftperform仅限2个参数
  • 您需要具有方法的确切签名(此处为#selector)

如果您可以将数组粘贴在第一个参数中,并且始终具有相同的签名,那么您就完成了。但是,如果您真的需要更进一步,那么您别无选择,只能选择ObjC,后者在Playground中不起作用。

您可以创建类似的Driver.m文件:

#import <Foundation/Foundation.h>
#import <objc/runtime.h>

id call (NSObject *callOn, NSString *callMethod, NSArray <NSObject *>*callParameters)
{
    void *result = NULL;
    unsigned int index, count;

    Method *methods = class_copyMethodList(callOn.class, &count);
    for (index = 0; index < count; ++index)
    {
        Method method = methods[index];

        struct objc_method_description *description = method_getDescription(method);
        NSString *name = [NSString stringWithUTF8String:sel_getName(description->name)];
        if ([name isEqualToString:callMethod])
        {
            NSMethodSignature *signature = [NSMethodSignature signatureWithObjCTypes:description->types];
            NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];

            NSObject *parameters[callParameters.count];
            for (int p = 0; p < callParameters.count; ++p) {
                parameters[p] = [callParameters objectAtIndex:p];
                [invocation setArgument:&parameters[p] atIndex:p + 2]; // 0 is self 1 is SEL
            }
            [invocation setTarget:callOn];
            [invocation setSelector:description->name];
            [invocation invoke];
            [invocation getReturnValue:&result];
            break;
        }
    }
    free(methods);

    return (__bridge id)result;
}

将其添加到桥接头中(让Swift知道ObjC中的内容):

// YourProjectName-Bridging-Header.h
id call (NSObject *callOn, NSString *callMethod, NSArray *callParameters);

并使用这样的Solution.swift进行调用:

import Foundation

class Solution: NSObject {

    override init() {
        super.init()
        // this should go in Driver.swift
        let result = call(self, "functionNameWithGreeting:name:", ["Hello", "solution"])
        print(result as Any)
    }

    @objc
    func functionName(greeting: String, name: String) -> String {
        print(greeting, name)
        return "return"
    }

}

输出:

Hello solution
Optional(return)

编辑:编译

要在命令行上同时编译ObjC和Swift,您可以先将ObjC编译为目标文件:

$ cc -O -c YouObjCFile.m

然后使用桥接头和目标文件编译您的Swift项目:

$ swiftc -import-objc-header ../Your-Bridging-Header.h YouObjCFile.o AllYourSwiftFiles.swift -o program

工作样本

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

通过带有参数的名称调用函数

来自分类Dev

通过反射C#调用参数中带有参数的方法

来自分类Dev

如何通过反射调用带有枚举(枚举)参数的方法?

来自分类Dev

无法通过反射调用带有varargs参数的方法-NoSuchMethodException

来自分类Dev

如何通过Kotlin中的反射获取参数名称?

来自分类Dev

lua函数调用中的参数名称

来自分类Dev

在方法调用中写入参数名称

来自分类Dev

通过带有委托参数的反射调用泛型方法的问题

来自分类Dev

是否有可能通过javascript中的函数名称获取参数

来自分类Dev

调用带有参数谷值反射的方法

来自分类Dev

如何使用反射调用带有.class(非对象)参数的java中的方法

来自分类Dev

jQuery-在.on()方法中带有参数的调用函数

来自分类Dev

Rails强大的参数名称中带有“点”

来自分类Dev

参数名称中带有[]的Ajax Post

来自分类Dev

通过反射调用具有命名参数的方法

来自分类Dev

通过反射调用具有命名参数的方法

来自分类Dev

如何通过反射获取通用参数名称

来自分类Dev

调用函数时声明参数名称

来自分类Dev

在onclick react中传递函数名称与通过回调调用函数名称之间有什么区别

来自分类Dev

使用Swift进行反射-获取类的函数名称

来自分类Dev

在Swift中使用函数参数名称

来自分类Dev

带简写参数名称的Swift函数

来自分类Dev

mockito:通过反射模拟参数的方法调用

来自分类Dev

在名称由字符串变量定义的类中调用已知函数(带有参数)

来自分类Dev

如何使用ctypes调用带有双下划线函数名称的DLL函数?

来自分类Dev

如何通过pyRserve调用名称中带有点的R函数?

来自分类Dev

在C ++中使用所有默认参数调用函数时使用参数名称

来自分类Dev

在C ++中使用所有默认参数调用函数时,请使用参数名称

来自分类Dev

在viewDidLoad中带有参数的SWIFT函数

Related 相关文章

  1. 1

    通过带有参数的名称调用函数

  2. 2

    通过反射C#调用参数中带有参数的方法

  3. 3

    如何通过反射调用带有枚举(枚举)参数的方法?

  4. 4

    无法通过反射调用带有varargs参数的方法-NoSuchMethodException

  5. 5

    如何通过Kotlin中的反射获取参数名称?

  6. 6

    lua函数调用中的参数名称

  7. 7

    在方法调用中写入参数名称

  8. 8

    通过带有委托参数的反射调用泛型方法的问题

  9. 9

    是否有可能通过javascript中的函数名称获取参数

  10. 10

    调用带有参数谷值反射的方法

  11. 11

    如何使用反射调用带有.class(非对象)参数的java中的方法

  12. 12

    jQuery-在.on()方法中带有参数的调用函数

  13. 13

    Rails强大的参数名称中带有“点”

  14. 14

    参数名称中带有[]的Ajax Post

  15. 15

    通过反射调用具有命名参数的方法

  16. 16

    通过反射调用具有命名参数的方法

  17. 17

    如何通过反射获取通用参数名称

  18. 18

    调用函数时声明参数名称

  19. 19

    在onclick react中传递函数名称与通过回调调用函数名称之间有什么区别

  20. 20

    使用Swift进行反射-获取类的函数名称

  21. 21

    在Swift中使用函数参数名称

  22. 22

    带简写参数名称的Swift函数

  23. 23

    mockito:通过反射模拟参数的方法调用

  24. 24

    在名称由字符串变量定义的类中调用已知函数(带有参数)

  25. 25

    如何使用ctypes调用带有双下划线函数名称的DLL函数?

  26. 26

    如何通过pyRserve调用名称中带有点的R函数?

  27. 27

    在C ++中使用所有默认参数调用函数时使用参数名称

  28. 28

    在C ++中使用所有默认参数调用函数时,请使用参数名称

  29. 29

    在viewDidLoad中带有参数的SWIFT函数

热门标签

归档