在 Swift 中从字符串调用方法

2023-12-12

从名称(字符串格式)调用方法有时很有用。
在 Swift 中,建议改变行为并使用闭包“动态”地执行某些操作,例如,您可以拥有一个函数字典,以名称作为键,以实现作为值。
然而,有时你只想简单地知道“如何去做”,这就是这个问题的原因。
那么,如何从名称字符串开始动态调用 Swift 方法呢?

在 Objective C 中,这很简单:

[self performSelector:NSSelectorFromString(@"aSelector")];

But performSelector在 Swift 中被禁止
还有其他选择吗?


在 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
}

然后快速地调用它

    let sampleClassInstance = ASampleClass()

    println(_performMethod("aTestFunction", sampleClassInstance))

该函数导致这些语句打印在日志上:

正确调用
test

因此,在 C 中创建 _performMethod() 替代方案应该不那么困难:

  • 自动创建函数签名(因为它似乎有一个逻辑:-)
  • 管理不同的返回值类型和参数

EDIT

在 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)

现在在二进制文件中我发现

000000010026d830t__TToFC7Perform9TestClass4testfT_T_

目前,我不太明白这背后的原因,但我会进一步调查

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

在 Swift 中从字符串调用方法 的相关文章

随机推荐

  • 数据绑定到方法的输出

    我正在尝试在 WPF 中显示方法的输出TextBox 我只是尝试一个简单的尝试 打印单个字符串3 in a TextBox 我正在尝试按照以下方式执行此操作 使用ObjectDataProvider
  • AngularJS - 基于 json 构建动态表

    给定一个像这样的 json name john colours id 1 name green id 2 name blue 和两个常规 html 输入
  • 停止 iPhone 中的声音

    SystemSoundID soundID NSString path NSBundle mainBundle pathForResource static ofType caf AudioServicesCreateSystemSound
  • 我应该使用 fseek SEEK_END [重复]

    这个问题在这里已经有答案了 我的问题很简单 我应该使用 fseek 和 SEEK END 来到达文件末尾然后获取它的长度吗 因为在男人身上有这样一句话 库实现允许不有意义地支持 SEEK END 因此 使用它的代码没有真正的标准可移植性 现
  • 如何在每 (n) 行后插入空行?

    我有这个脚本 ECHO OFF FOR f tokens 2 delims a IN findstr l
  • Python numpy.fft 改变步幅

    亲爱的 stackoverflow 社区 今天我发现在高端集群架构上 尺寸为 1921 x 512 x 512 的 2 个立方体的元素乘法大约需要 27 秒 这太长了 因为在当前实现中 我必须执行至少 256 次这样的计算才能对功率谱进行方
  • 如何使用 PHP 打印图像:打印机

    我有一台直接连接到我的 PC 的打印机 我可以使用 PHP 打印文本 我想知道的是 如何使用相同的 php 函数打印图像 thanks 尝试看看http www php net manual en function printer draw
  • 返回局部变量

    我今天遇到一个关于局部变量的问题 我了解到 int somefunc int x 5 return x int y somefunc do something 是不好的 不安全的 等等 我想情况是一样的 int somefunc int x
  • 如何根据多个条件提取data.table的值?

    如何根据多个条件提取data table的值 我需要一个函数 根据其他两个列值返回 data table 列的值 require data table dt lt data table base c of of of lead and ba
  • RawPostDataException:从请求的数据流读取后无法访问正文

    我在 Google Cloud 上托管一个网站 一切都运行良好 然后突然间我开始收到此错误 01 16 22 222 Internal Server Error api v1 auth login base data home apps s
  • 以编程方式连接到 Android Q 中的 Wifi

    我有这个功能可以连接Wifi网络 在Android 10以下它工作正常 但是当我在Android 10上尝试时 我连接成功了 但是没有互联网 我知道这是Android 10 中的一个错误但我发现了这个应用可以毫无问题地从 Android 1
  • 从 Promise 结果导出 Node 模块

    我正在尝试重写一个模块以返回与以前不同的值 但现在它使用异步调用来获取该值 和child process如果重要的话 我已将其包装在 Promise 中 但这对我来说并不重要 它可以在原始的 child process 回调中 但问题是我无
  • Web Api 的 Xml 文档如何包含主项目之外的文档?

    The 文档用于将 XmlDoc 集成到 Web Api 项目中似乎只能处理所有 API 类型都是 WebApi 项目一部分的情况 特别是 它讨论了如何将 XML 文档重新路由到App Data XmlDocument xml并取消注释配置
  • 关于如何衡量IR评估的排名、AP、MAP、召回率的一些想法和方向

    我有关于如何评估信息检索结果好坏的问题 例如计算 相关文档的Rank Recall Precision AP MAP 目前 一旦用户输入查询 系统就能够从数据库中检索文档 问题是我不知道如何做评估 我得到了一些公共数据集 例如 克兰菲尔德集
  • GSC 消息:修复 Android 应用程序的深层链接。错误“不支持 Intent URI”

    续自https productforums google com forum topic webmasters wZEY QZicxg context place forum webmasters 谷歌搜索控制台消息 本周我们收到一条 GS
  • Recyclerview 无法正确显示列表

    我正在尝试使用视图绑定创建简单的 Recyclerview 问题是我的回收者视图没有分隔线 看来我所有的物品都是 排成一排 这是我的代码 这是activity main xml
  • Android 应用程序中的 Firebase 规则验证和捕获验证失败

    Design 可以登录应用程序的用户 登录用户可以创建客户 该客户将存储在node其值将是当前登录的用户ID 当前数据库值 customers UserId1 custId1 customerCode thk customerLimit 5
  • 如何使用 ng-options 在选择上设置提示?

    我有一个使用 ng options 来填充选择的选择 如下所示
  • Fabric.js - 将调整大小/缩放约束到画布/对象

    使用 Fabric js 时 如何将对象限制为仅在画布 或我的情况下的另一个对象 的范围内调整大小 缩放 目前 我正在处理object scaling event Typescript being used onObjectScaling
  • 在 Swift 中从字符串调用方法

    从名称 字符串格式 调用方法有时很有用 在 Swift 中 建议改变行为并使用闭包 动态 地执行某些操作 例如 您可以拥有一个函数字典 以名称作为键 以实现作为值 然而 有时你只想简单地知道 如何去做 这就是这个问题的原因 那么 如何从名称