In viewDidLoad I would scan all UITextField and a set addTarget with the code below. I have 3 UITextField but only 1 of that is found.
for subview in self.view.subviews
{
println(subview)
if (subview.isKindOfClass(UITextField))
{
var textField = subview as UITextField
textField.addTarget(self, action: "textFieldDidReturn:", forControlEvents: UIControlEvents.EditingDidEndOnExit)
textField.addTarget(self, action: "textFieldDidBeginEditing:", forControlEvents: UIControlEvents.EditingDidBegin)
}
}
The view is very simple, built for exercise. 1 UIimageView, 3 UITextField, 1 button, 1 label. But the println(subview) display only
<UITextField: 0x7a739cf0; frame = (57 430; 290 30); text = ''; clipsToBounds = YES; opaque = NO; autoresize = RM+BM; layer = <CALayer: 0x7a739c90>>
<UIImageView: 0x7a742d70; frame = (0 0; 0 0); autoresize = RM+BM; userInteractionEnabled = NO; layer = <CALayer: 0x7a742ef0>>
<_UILayoutGuide: 0x7a7430d0; frame = (0 0; 0 0); hidden = YES; layer = <CALayer: 0x7a743270>>
<_UILayoutGuide: 0x7a743650; frame = (0 0; 0 0); hidden = YES; layer = <CALayer: 0x7a7436d0>>
The first UITextField is found and set, the others not. Why? Where am I wrong?
In other word. What is the right way to scan all the objects in a view?
Thanks
The problem is merely that you are running your code too soon. Your code is in your view controller superclass's viewDidLoad
. At that time, its view has loaded, but its subclass's view has not - and the subclass's view is where all the subviews are. So the result you are getting for your logging code, while surprising, is perfectly correct — at the moment that the code runs.
Just move your logging code into an implementation of viewDidAppear:
or some other method that is called after the interface is completely ready, and you'll get the result you expect. I tested that with your project and it works fine.
I have created a simple recursive method to find all textfields in some view,
func findAllTextFieldsInView(view: UIView) -> [UITextField]{
var allTextFields = [UITextField]()
for aView in view.subviews{
if aView is UITextField{
allTextFields.append(aView as UITextField)
}
let textFieldsInSubViews = findAllTextFieldsInView(aView as UIView)
if textFieldsInSubViews.count > 0{
allTextFields += textFieldsInSubViews
}
}
return allTextFields
}
Call this method and this will return all the textfield in the view and it returns array of all textfield,
findAllTextFieldsInView(self.view)
Adding action to the textfields is quite similar to the method above, I recurse all the subviews to find textfields and add target to it.
func addControlEventToAllTextFieldsInView(view: UIView){
for aView in view.subviews as [UIView]{
if let textField = aView as? UITextField{
textField.addTarget(self, action: "textFieldDidReturn:", forControlEvents: UIControlEvents.EditingDidEndOnExit)
textField.addTarget(self, action: "textFieldDidBeginEditing:", forControlEvents: UIControlEvents.EditingDidBegin)
}
addControlEventToAllTextFieldsInView(aView)
}
}
My code kept crashing for the method to find all textviews (in my case, textfield & textviews). So I modified it slightly and this seems to work fine for me:
func getAllTextInputViews(inView:UIView) -> [UITextInput] {
var allTextFields = [UITextInput]()
for aView in inView.subviews {
if aView.isHidden {
continue
}
else if aView is UITextField{
allTextFields.append(aView as! UITextField)
}
else if aView is UITextView{
allTextFields.append(aView as! UITextView)
}else {
let textFieldsInSubViews = getAllTextInputViews(inView:aView as UIView)
if textFieldsInSubViews.count > 0{
allTextFields += textFieldsInSubViews
}
}
}
return allTextFields
}