我收到以下消息:
[UTextField retain]:发送到已解除分配实例的消息。
我理解这个信息,但我不知道发送了什么"信息",以及如何阻止它发生。。。。
此代码产生错误:
func dismissController() {
self.view.endEditing(true)
self.dismissViewControllerAnimated(false, completion: nil)
}
虽然以下操作"正常",但我不确定为什么在解雇控制器之前必须延迟:
func dismissController() {
self.view.endEditing(true)
let delay = 0.75 * Double(NSEC_PER_SEC)
let time = dispatch_time(DISPATCH_TIME_NOW, Int64(delay))
dispatch_after(time, dispatch_get_main_queue()) { () -> Void in
self.dismissViewControllerAnimated(false, completion: nil)
}
}
编辑:(几乎是完整的代码):
@IBOutlet weak var locationTextView: UITextField!
@IBOutlet weak var userIDTextView: UITextField!
var treeLocationArray = NSMutableArray()
var treeUserIDArray = NSMutableArray()
let pickerView=UIPickerView()var pickerButton=UIButton()var keyboardButton=UIButton()var locationIsSelected=真实
override func viewDidLoad() {
super.viewDidLoad()
//....
locationTextView.delegate = self
userIDTextView.delegate = self
//Get the Plist... etc
treeLocationArray = dict?.objectForKey("Location") as! NSMutableArray
treeUserIDArray = dict?.objectForKey("UserID") as! NSMutableArray
locationTextView.text = userPrefs.objectForKey("DefaultLocation") as? String
userIDTextView.text = userPrefs.objectForKey("DefaultName") as? String
locationTextView.text = userPrefs.objectForKey("DefaultLocation") as? String
/// Create a view for the Accessory View
let customView = UIView(frame: CGRectMake(0, 0, 10, 50))
customView.backgroundColor = UIColor.lightGrayColor()
/// Setup the picker button
pickerButton = UIButton(frame: CGRectMake(60 , 8, 32, 32) )
pickerButton.setImage(UIImage(named:"dropIcon"), forState: .Normal)
pickerButton.tintColor = UIColor.blueColor()
pickerButton.addTarget(self, action: #selector(UserDefaultsViewController.pickerTapped), forControlEvents: UIControlEvents.TouchUpInside)
customView.addSubview(pickerButton)
/// Setup the keyboard button
keyboardButton = UIButton(frame: CGRectMake(10 , 8, 32, 32) )
keyboardButton.setImage(UIImage(named:"keyboardIcon"), forState: .Normal)
keyboardButton.tintColor = UIColor.blueColor()
keyboardButton.addTarget(self, action: #selector(UserDefaultsViewController.keyboardTapped), forControlEvents: UIControlEvents.TouchUpInside)
customView.addSubview(keyboardButton)
locationTextView.inputAccessoryView = customView
userIDTextView.inputAccessoryView = customView
}
func textFieldDidBeginEditing(textField: UITextField) {
if textField == locationTextView {
locationIsSelected = true
}
if textField == userIDTextView {
locationIsSelected = false
}
self.pickerView.reloadAllComponents()
}
func keyboardTapped(){
if locationIsSelected {
locationTextView.resignFirstResponder()
locationTextView.inputView = nil
locationTextView.becomeFirstResponder()
}
else {
userIDTextView.resignFirstResponder()
userIDTextView.inputView = nil
userIDTextView.becomeFirstResponder()
}
}
func pickerTapped(){
if locationIsSelected {
locationTextView.resignFirstResponder()
locationTextView.inputView = nil
locationTextView.inputView = pickerView
locationTextView.becomeFirstResponder()
}
else {
userIDTextView.resignFirstResponder()
userIDTextView.inputView = nil
userIDTextView.inputView = pickerView
userIDTextView.becomeFirstResponder()
}
}
func numberOfComponentsInPickerView(pickerView: UIPickerView) -> Int {
return 1
}
func pickerView(pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
var numberOfComponents = Int()
if locationIsSelected {
numberOfComponents = treeLocationArray.count
}
else {
numberOfComponents = treeUserIDArray.count
}
return numberOfComponents
}
func pickerView(pickerView: UIPickerView, numberOfRowsInSection section: Int) -> Int {
var numberOfComponents = Int()
if locationIsSelected {
numberOfComponents = treeLocationArray.count
}
else {
numberOfComponents = treeUserIDArray.count
}
return numberOfComponents
}
func pickerView(pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
var componetString = String()
if locationIsSelected {
componetString = (treeLocationArray[row] as? String)!
}
else {
componetString = (treeUserIDArray[row] as? String)!
}
return componetString
}
func pickerView(pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
if locationIsSelected {
if treeLocationArray.count >= 1 {
locationTextView.text = treeLocationArray[row] as? String
}
}
else {
if treeUserIDArray.count >= 1 {
userIDTextView.text = treeUserIDArray[row] as? String
}
}
}
发生此问题是因为您调用了disseViewControllerAnimated。由于VC的生命周期,此VC持有的所有对象都将被释放。这意味着,所有在解除后使用UI的操作都不是内存安全的。
来自文件:
此方法查看当前视图及其子视图层次结构当前为第一个响应程序的文本字段。如果它找到一个,它要求该文本字段辞去第一响应者的职务。如果力参数设置为true时,甚至从不询问文本字段;是的被迫辞职。
所以,正如我所猜测的,当endEditing正在彻底研究层次结构时,你的VC已经被释放了。这是唯一一个可能导致记忆问题的原因。
为什么在解雇前需要调用endEditing?不需要这个调用就可以简单地解雇VC。如果您有逻辑,这取决于endEditing-将其分离并调用,而不是endEditing。希望这能有所帮助。
更新:
尝试在视图中调用endEditing WillDisappear-这会触发视图在被解雇之前辞去第一响应者的职务。