在 Swift 中,您应该使用闭包并改变您的方法。
但是,如果您想使用performSelector 动态调用仅给出字符串签名的方法,尽管它本身不支持,但我已经找到了方法。
可以为 performSelector 创建一个 C 替代方案:
- 甚至适用于原生 swift 类(非 Objective-c)
- 从字符串中获取选择器
但是实现它的完整版本并不是那么简单,并且需要在 C 中创建方法。
在 C 语言中,我们有 dlsym(),一个函数,它返回一个指向给定 char 符号的函数的指针。
好吧,阅读这篇有趣的帖子:
http://www.eswick.com/2014/06/inside-swift/
我学到了很多关于 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
}
然后在 swift 端调用它
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_
目前我还不太了解这背后的原因,但我会进一步调查