从名称(以String格式)调用方法有时很有用
在Swift中,建议改变行为并使用闭包来“动态地”执行某些操作,例如,您可以使用函数字典,将名称作为键,将实现作为值。
但是,有时你想简单地知道“怎么做”,这就是这个问题的原因
那么,如何动态调用一个Swift方法,从它的名字开始,作为字符串?
在目标C中,这很简单:
[self performSelector:NSSelectorFromString(@"aSelector")];
但是performSelector
在Swift中被禁止了
还有其他选择吗?
答案 0 :(得分:31)
在Swift中,你应该使用闭包并改变你的方法。
但是,如果你想使用performSelector
来动态调用只给出它的String签名的方法,尽管本机不支持它,我已经找到了如何做到这一点。
可以为performSelector创建一个C替代:
然而,实现它的完整版本并不是那么简单,并且有必要在C中创建该方法。
在C中我们有dlsym()函数,它返回一个指向char符号的函数的指针。 那么,阅读这篇有趣的帖子: http://www.eswick.com/2014/06/inside-swift/ 我学到了很多关于斯威夫特的有趣事情。Swift实例方法是具有特定签名的普通函数,如此
_TFC14FirstSwiftTest12ASampleClass13aTestFunctionfS0_FT_CSo8NSString
其中“self”值作为最后一个参数传递
总之,你可以直接从c方面调用它而不需要任何桥接,重建正确的函数签名就足够了。 在上面的签名中,有项目的名称(FirstSwiftTest)和长度(14),类的名称(ASampleClass)和长度(12),函数的名称(aTestFunction)和长度(13) ),然后其他值作为返回类型ecc ecc。有关其他详细信息,请查看上一个链接
上面的函数代表了这个:
class ASampleClass
{
func aTestFunction() -> NSString
{
println("called correctly")
return NSString(string: "test")
}
}
好吧,在c方面,我能够创建这个功能
#include <stdio.h>
#include <dlfcn.h>
typedef struct objc_object *id;
id _performMethod(id stringMethod, id onObject)
{
// ...
// here the code (to be created) to translate stringMethod in _TFC14FirstSwiftTest12ASampleClass13aTestFunctionfS0_FT_CSo8NSString
// ...
id (*functionImplementation)(id);
*(void **) (&functionImplementation) = dlsym(RTLD_DEFAULT, "_TFC14FirstSwiftTest12ASampleClass13aTestFunctionfS0_FT_CSo8NSString");
char *error;
if ((error = dlerror()) != NULL) {
printf("Method not found \n");
} else {
return functionImplementation(onObject); // <--- call the function
}
return NULL
}
然后迅速调用它
let sampleClassInstance = ASampleClass()
println(_performMethod("aTestFunction", sampleClassInstance))
该函数导致这些语句打印在日志中:
正确调用
的测试强>
因此在C中创建一个_performMethod()替代方案应该不那么困难:
<强> 修改 强>
在Swift 2中(也许在Beta3中,我没有尝试)似乎允许performSelector()(并且你只能在NSObject子类上调用它)。检查二进制文件,现在似乎Swift创建了可由performSelector专门调用的静态函数。
我创建了这个类
class TestClass: NSObject {
func test() -> Void {
print("Hello");
}
}
let test = TestClass()
let aSel : Selector = NSSelectorFromString("test")
test.performSelector(aSel)
现在在二进制文件中找到
000000010026d830 t __TToFC7Perform9TestClass4testfT_T _
目前,我并不清楚这背后的原因,但我会进一步调查
答案 1 :(得分:5)
您可以通过这种方式从String调用方法:
let selectorName = "name"
perform(Selector(selectorName))
仅当您的类是NSObject
答案 2 :(得分:3)
class MyClass:NSObject
{
required public override init() { print("Hi!") }
public func test(){
print("This is Test")
}
public class func static_test(){
print("This is Static Test")
}
}
if let c: NSObject.Type = NSClassFromString("TestPerformSelector.MyClass") as? NSObject.Type{
let c_tmp = c.init()
c_tmp.perform(Selector("test"))
c.perform(Selector("static_test"))
}