我想知道在 id
上调用方法的 Swift 等价物是什么,其中方法的可用性在运行时确定。具体来说,我希望在 Swift 中执行此模式:
-(IBAction) handleEvent:(id) sender {
BOOL didDisable = NO;
if([sender respondsToSelector:@selector(setEnabled:)]) {
[sender setEnabled:NO];
didDisable = YES;
}
[self doSomethingAsyncWithCompletionHandler:^{
if(didDisable) {
[sender setEnabled:YES];
}
}];
}
最大的问题是 setEnabled:
在 Swift 中作为属性导入(例如 UIBarItem
),以下构造均无法编译
func handleEvent(sender: AnyObject) {
// Error: AnyObject does not have a member named "enabled"
sender.enabled? = false
// Error: (BooleanLiteralCompatible) -> _ is not identical to Bool
sender.setEnabled?(false)
}
最佳答案
实际上,您可以按照与之前完全相同的方式进行操作:调用 respondsToSelector:
。事实上,这正是您建议的表达式所做的:
sender.setEnabled?(false)
该表达式实际上是一个简写 - 它首先调用 respondsToSelector:
,然后仅当 respondsToSelector:
测试通过时才调用 setEnabled:
。不幸的是,正如您所说,您无法编译该代码。然而,这只是 Swift 已知的可用方法库中的一个怪癖。事实是,虽然编译它有点棘手,但它是可以做到的 - 一旦你编译它,它的行为就像你期望的那样。
但是,我不打算解释如何让它通过编译,因为我不想鼓励这种诡计。 Swift 不鼓励这种动态消息传递。通常,Swift 不需要动态消息传递技巧,例如键值编码、内省(introspection)等,并且不符合 Swift 的强类型方法。最好以 Swift 的方式做事,通过选择性地转换为您有理由相信它可能是并且具有 enabled
属性的东西。例如:
@IBAction func doButton(sender: AnyObject) {
switch sender {
case let c as UIControl: c.enabled = false
case let b as UIBarItem: b.enabled = false
default:break
}
}
或者:
@IBAction func doButton(sender: AnyObject) {
(sender as? UIControl)?.enabled = false
(sender as? UIBarItem)?.enabled = false
}
关于objective-c - 在 `id` 上设置属性的快捷方式是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30870575/