当与RIS-C运行时接口时,似乎允许选择器名称包含“非法”字符。可以使用这种选择器添加新方法,并以代码中不可能的方式调用它们。
让我给予一个例子:
final class Test: NSObject {
@objc func test() {
print("This is Sparta!")
}
}
// Xcode indeed shows a warning "String literal is not a valid Objective-C selector"
let selector = Selector("invalid? !@#$%^&*()")
// let's add a new method, having the same implementation as an existing one
let testMethod = class_getInstanceMethod(Test.self, #selector(Test.test))!
let added = class_addMethod(Test.self, selector, method_getImplementation(testMethod), "v@:")
print("class_addMethod result: \(added)")
// let's see if calling the method works
Test().perform(selector)
字符串
上面的代码创建了一个具有无效(?)名称的选择器,使用该选择器向测试类添加一个新方法,并在之后调用该方法。当然,不能直接通过点表示法调用该方法,因为它们会得到编译器错误,但是,新添加的方法可以通过performSelector
调用。
令我惊讶的是,上面的代码生成了以下输出:
class_addMethod result: true
This is Sparta!
型
这意味着我们可以在运行时定义方法,如果在类声明中编写,方法的名称将生成编译错误。
我找不到任何支持这种行为的文档,直观地说,由于选择器名称是空字符串,动态方法查找应该适用于任何类型的字符串。
这是预期的行为吗?如果是,选择器名称的内容是否有任何限制(可能除了长度)?
1条答案
按热度按时间ddhy6vgd1#
在Objetive-C的语法中,
@selector
的名字是Identifiers
标识符一个C++标识符是一个用于标识变量、函数或任何其他用户定义项的名称。标识符以字母A到Z或a到z或下划线开头,后跟零个或多个字母、下划线和数字(0到9)。
在标识符中不允许使用@、$和%等标点符号。在编程语言中,Manpower和manpower是两个不同的标识符。下面是一些可接受的标识符示例:
字符串
https://www.tutorialspoint.com/objective_c/objective_c_basic_syntax.htm
这是预期的行为吗?如果是,选择器名称的内容是否有任何限制(可能除了长度)?
我认为这是预期的行为; Obj-c运行时保留了一个选择器的哈希表,任何可以在NSString中编码和哈希的东西都应该工作,因此有效标识符的检查是在编译时而不是运行时进行的。