我在理解addtarget的工作原理时遇到了一些麻烦。我在下面的快速课程中复制了我的问题。该按钮在屏幕上正确显示,但是当我按下它时,scala> case class Calendar(id:Int,name:String,description:Option[String],owner:Int)
defined class Calendar
scala> case class CalendarRow(id:Int,name:String,description:Option[String],settings:Seq[String]=Seq.empty)
defined class CalendarRow
scala> def append(calendars:Calendar*) = calendars.map(c => CalendarRow(c.id,c.name,c.description))
append: (calendars: Calendar*)Seq[CalendarRow]
scala> val calendar1 = Calendar(1,"first",Option("my first calendar"),1)
calendar1: Calendar = Calendar(1,first,Some(my first calendar),1)
scala> val calendar2 = Calendar(2, "second",None,1)
calendar2: Calendar = Calendar(2,second,None,1)
scala> val list = append(calendar1,calendar2)
list: Seq[CalendarRow] = ArrayBuffer(CalendarRow(1,first,Some(my first calendar),List()), CalendarRow(2,second,None,List()))
功能被调用而不是PopupMenuViewController.pressed
功能。
的为什么吗
handlerClass.pressed
FIX:感谢Carl指出这一点。应将import Foundation
import UIKit
import CoreLocation
class PopupMenuViewController : UIViewController
{
class handlerClass
{
func pressed(sender: UIButton!) {
/// **IT SEEMS LIKE THE CALL FROM ADDTARGET SHOULD GO HERE...**
var alertView = UIAlertView();
alertView.addButtonWithTitle("Ok");
alertView.title = "title";
alertView.message = "message";
alertView.show();
}
}
func pressed(sender: UIButton!) {
// **BUT INSTEAD IT ENDS UP HERE!!!!**
var alertView = UIAlertView();
alertView.addButtonWithTitle("Ok");
alertView.title = "title";
alertView.message = "message";
alertView.show();
}
override func viewDidLoad()
{
super.viewDidLoad()
let hc = handlerClass() // make me a member variable to fix this problem
let button1 = UIButton()
button1.frame = CGRectMake(10, 400, 100, 50)
button1.backgroundColor = UIColor.lightGrayColor().colorWithAlphaComponent(0.9)
button1.layer.cornerRadius = 10.0
button1.setTitle("Button ", forState: UIControlState.Normal)
// ** THE OFFENDING ADD TARGE CALL **
button1.addTarget(hc, action: "pressed:", forControlEvents: .TouchUpInside)
self.view.addSubview(button1)
}
}
提升为成员变量
答案 0 :(得分:1)
来自Apple docs:
目标对象 - 即操作所针对的对象 邮件已发送。如果为零,则搜索响应者链 愿意回应行动信息的对象。
但是你指定了目标对象,那么最近怎么办?另一个有趣的引用:
调用此方法时,不会保留目标。
你在一个函数中创建了这个对象,只存储在那里,所以一旦块结束,保留计数结束于0,变量现在为零。
为避免这种情况,您可以在函数之前将其作为属性添加,然后在函数中实例化。
答案 1 :(得分:0)
感谢卡尔的评论。
最初的问题实际上有点复杂,我在长按识别器中创建了一个PopupMenuViewController。
func mapView(mapView: GMSMapView!, didLongPressAtCoordinate coordinate: CLLocationCoordinate2D)
{
let tapPoint = coordinate
let menu = PopupMenuViewController();
self.presentVC(menu)
// menu is deallocated before exit (and before it can respond to pressed)
}
PopupMenuViewController中的被按下的函数在它响应之前被销毁了。
答案 2 :(得分:0)
我想我知道造成这种奇怪行为的原因。首先,您的let hc = handlerClass()
变量不会保留在viewDidLoad
范围之外。换句话说,在viewDidLoad完成运行后,它实际上不再存在。
每当你使用目标行动模式时,你需要保证当事件被触发时,目标仍在某个地方。
根据另一个答案进行更新:因为hc
变量已被释放,但触发了操作的时间,最终被调用的对象是响应者链上的下一个响应pressed:
的对象
对此的一个解决方案是向父类添加var handler: HandlerClass?
,并在创建处理程序时存储处理程序。
但是,当我在本地测试中执行此操作时,我遇到了另一个奇怪的错误,即(处理程序类的)实例没有响应pressed:
。直到我从NSObject下降HandlerClass
后才能按预期工作。这是我最终得到的工作示例:
import UIKit
class ViewController: UIViewController {
var handler: HandlerClass?
class HandlerClass : NSObject
{
func pressed(sender: UIButton!) {
/// **THE CALL FROM ADD TARGET ENDS UP HERE**
let alertView = UIAlertView();
alertView.addButtonWithTitle("Ok");
alertView.title = "HandlerClass";
alertView.message = "HandlerClass";
alertView.show();
}
}
func pressed(sender: UIButton!) {
// **NOT HERE**
let alertView = UIAlertView();
alertView.addButtonWithTitle("Ok");
alertView.title = "non handler pressed";
alertView.message = "non handler message";
alertView.show();
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
// let hc = HandlerClass()
let button1 = UIButton()
button1.frame = CGRectMake(100, 100, 100, 100)
button1.backgroundColor = UIColor.lightGrayColor().colorWithAlphaComponent(0.9)
button1.layer.cornerRadius = 10.0
button1.setTitle("Button ", forState: UIControlState.Normal)
view.addSubview(button1)
handler = HandlerClass()
button1.addTarget(handler, action: "pressed:", forControlEvents: .TouchUpInside)
}
}