我有一个名为的类的实例,Solution
并且我有一个函数名称作为functionName
要在该Solution
实例上调用的字符串solutionInstance
。我在数组中有函数的参数,我也想传递这些参数。
我正在使用Swift编译器将我的所有.swift
文件(swiftc
一起枚举的文件,然后-o
是输出文件名)一起编译,然后运行最终输出。
这是我在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中传递参数数组(使用反射)?如何更改我的设置以实现此目的(导入库等)
谢谢!
参考文章首先,正如您所指出的,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")
}
这里还有其他关注点:
perform
仅限2个参数如果您可以将数组粘贴在第一个参数中,并且始终具有相同的签名,那么您就完成了。但是,如果您真的需要更进一步,那么您别无选择,只能选择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:¶meters[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] 删除。
我来说两句