我有一个ViewController及其视图:
class GraphicViewController: UIViewController {
var timerVC!:NSTimer
override func viewDidLoad() {
(view as GraphicView).timerV = NSTimer.scheduledTimerWithTimeInterval(interval, target: self, selector: Selector("doSomeWork"), userInfo: nil, repeats: true)
}
}
class GraphicView: UIView {
var timerV:NSTimer!
func doSomeWork(someParam:NSString)->Double {/*code*/}
}
它会导致错误的选择器错误。我有两个问题:
1)如何使用带有参数的Selector并从func返回?
2)如何从视图中选择func而不是在VC中创建这样的func?
答案 0 :(得分:7)
触发错误的原因是您没有提供正确的目标。这就是目标 - 动作范例的工作原理(或者至少,它在Objective C中是如何工作的,我真的希望他们能够更新Swift API以利用整个函数作为对象的哲学):
target: (id)target, selector:(Selector)selector
。这应该告诉您,该API计划调用一个方法,您必须在对象上提供您必须提供的方法。self
作为目标时,您告诉NSTimer调用名为" doSomeWork"的方法。在您的View Controller上,它没有实现这样的方法。难怪它会触发关于无法识别的选择器的错误!
此外,如果您确实将视图作为目标传递,那么会触发错误,因为与该方法关联的正确选择器将是"doSomeWork:"
,如在Objective C方法签名中那样。这是最接近正确的实施方式:
class GraphicViewController: UIViewController {
var timerVC!:NSTimer
override func viewDidLoad() {
let gView = view as GraphicView
gView.timerV = NSTimer.scheduledTimerWithTimeInterval(interval, target: gView, selector: Selector("doSomeWork"), userInfo: nil, repeats: true)
}
}
class GraphicView: UIView {
var timerV:NSTimer!
func doSomeWork() {/*code*/}
}
根据参数并返回:根据目标 - 动作范例,您不应使用您正在调用的方法的任何返回值。目标操作提供了一种机制,使目标与发送方对象(NSTimer)进行通信:如果您提供的选择器不接受任何参数(即它不以冒号结尾),则调用该方法时不带任何参数;如果选择器确实期望一个参数(即它以冒号结束),则发送方将调用它作为唯一参数传递自己。显然,您必须相应地更新被调用的方法:
class GraphicView: UIView {
var timerV:NSTimer!
func doSomeWork(sender: NSTimer!) {
/* do some work involving sender */
}
}
关于最后一个问题,如果我理解正确,你要求一种方法来避免从UIViewController内部引用GraphicView中定义的方法。这实际上是可行的,但是这不会让你在不使用目标动作的情况下设置NSTimer(截至今天)。当然,实现整个事情的更方便的方法可能是:
class GraphicViewController: UIViewController {
override func viewDidLoad() {
let gView = view as GraphicView
gView.setupTimer()
}
}
class GraphicView: UIView {
var timer: NSTimer!
func doSomeWork(sender: NSTimer!) {
/* code */
}
func setupTimer() {
timer = NSTimer.scheduledTimerWithTimeInterval(interval, target: self, selector: Selector("doSomeWork:"), userInfo: nil, repeats: true)
}
}
在此实现中,将self
作为目标传递是有意义的,因为视图正在设置计时器以自行调用方法。这样,您可以通过创建上面的临时常量然后访问其timer
属性,从视图控制器内部访问计时器。