dhemery / victor

A Java driver for iOS applications
MIT License
11 stars 4 forks source link

Simulate UIControlEventEditingChanged #9

Closed mritunjayonemail closed 12 years ago

mritunjayonemail commented 12 years ago

Hi,

We are automating Xcode application using frank and victor.We are facing problem in automating one of the feature. In our Xcode there is text field on which event 'UIControlEventEditingChanged' is defined. Basically there is a passcode(textfield), on edit of this textfield we want some function to be executed. So on this particulate text field 'UIControlEventEditingChanged' is defined. This event will be triggered only if user inputs something in the passcode text field using keyboard touch.

But problem we are facing is that from our Victor code we are setting the value of this text field, but it is not triggering the 'UIControlEventEditingChanged' event. 'setText' method will simply set the value of text but it will not trigger 'UIControlEventEditingChanged' event reason is that value of the text is not getting changed by touch of the keyboard.

We tried several approached but none of them are working, Kindly suggest how we can simulate this behaviour. We urgently need your help in this.

Regards, Mritunjay

dhemery commented 12 years ago

There are two ways to fire the event. One way is through Java, like this:

  IosView myTextfield = ... ;

  // The bit as defined in the UIControl documentation.
  long UIControlEventEditingChanged = 1 << 17;

  // This just sets the text field value without notifying anyone.
  myTextField.sendMessage("setText:", "some new text");

  // This fires the UIControlEventEditingChanged event,
  // sending each target the appropriate action message.
  myTextField.sendMessage("sendActionsForControlEvents:", UIControlEventEditingChanged);

NOTE: This solution DOES NOT post the required "UITextFieldTextDidChangeNotification" notification. I don't know a way to post notifications directly through Frank. For that, you have to write an Objective-C method. Also, this solution bypasses the text field delegate's opportunity to refuse the new text ( by returning NO from textField:shouldChangeCharactersInRange:replacementText:).

Given those problems, I prefer the second way to fire the event. Add a category method to UITextField that does the following:

  1. Ask the delegate whether the view should add the new text. If no, return without making a change.
  2. Set the text property with the appropriate text.
  3. Post the "UITextFieldTextDidChangeNotification" notification.
  4. Fire the UIControlEventEditingChanged event.

Then instead of sending setText:, call this new method instead.

My latest implementation of that method starts on line 22 of this file: http://bit.ly/Ju48CL

Even this is slightly risky. If you call it when the text field is not first responder, the delegate may not be prepared to receive the text. So it's best to make sure you tap the field before calling this method.

I'm considering adding another condition to that method, to make it throw an exception if the text field is not currently first responder.

mritunjayonemail commented 12 years ago

Hi Dale, Thanks for the reply.

Just to conform, to solve this problem, 1) Add UITextField+DFX.h and UITextField+DFX.m in the XCode project. 2) After the line 27of UITextField+DFX.m send notification to the observer.

Is this will solve our problem? Please let me now if i wrongly understood your reply.

Regards, Mritunjay

On Sat, May 19, 2012 at 2:07 AM, Dale Emery < reply@reply.github.com

wrote:

As you've discovered, the problem is that 'setText:' merely displays the text. It does not inform the delegate or send notifications.

So I wrote a few helper methods that link into the application along with Frank (and Igor). You can see those here, in the UITextField+DFX category: http://bit.ly/KpN8Js

The method 'DFX_replaceTextAtLocation:length:withText:' does all the work: First it asks the delegate whether it's okay to replace the text. If so, it sets the text field.

NOTE: This method DOES NOT send 'UIControlEventEditingChanged' events to observers. It only calls the delegate. Eventually I'll make it post the 'UIControlEventEditingChanged' event. I didn't implement that here because I don't (yet) know enough about sending events, and the app I'm testing doesn't have any observers for that event.

But it should be easy enough to do. If you know how to post an event, do that after line 27 of the UITextField+DFX.m file.


Reply to this email directly or view it on GitHub: https://github.com/dhemery/victor/issues/9#issuecomment-5795144

Regards, Mritunjay

dhemery commented 12 years ago

I believe that will solve the problem. I am reluctant to speak definitively here, because until I received your issue I did not know that there were such things as control events. I knew about notifications, but I did not know about events. So there are possibly other things that I don't yet know.

I have a new version of the method with two additional lines: http://bit.ly/Ju48CL

Line 27 sends a "UITextFieldTextDidChangeNotification" to observers. Line 28 fires the UIControlEventEditingChanged event.

I can say this with authority: In my few small experiments, the new version of UITextField+DFX sends the notification and fires the event. In my sample application (see http://bit.ly/K8USSA), the master view controller is registered as an observer for the text change notification, and is also hooked up (via the storyboard/nib) to receive "editing changed" events.

When I run my sample app in the simulator, both of these methods are called when I edit text manually.

When I send a DFX_setText: message (or similar) via Victor, both of these methods are called.

So I think that will solve the problem for you.

By the way, the "DFX" in the category name and method prefixes means "Dale's Frank eXtensions." You're free to use that, of course, but you may wish to use a prefix more relevant to your organization.

dhemery commented 12 years ago

Also, I want to offer a slight distinction in your terminology (a distinction I myself discovered only yesterday): In order to simulate the UIControlEventEditingChanged event, you don't "send a notification to the observer," you "invoke the action on the target." These are very similar ideas in the abstract, but the Objective-C mechanisms are quite different.

The "notifications and observers" mechanism is handled by an application-wide singleton NSNotificationCenter. Observers register with the notification center, and publishers call NSNotificationCenter methods to publish notifications. The singleton NSNotificationCenter maintains the list of observers, what notifications they've subscribed to, and what message to send to each observer.

On the other hand, "control events" are handled entirely by UIControl objects. "Targets" register for events by making connections in the nib (or manually in the code). The control itself maintains the list of targets, what events they've registered for, and the "action" to invoke when the event fires. Then at the appropriate time, the control (or some iOS thing) tells the control to "send the actions" for some control event. The control looks up its own private list of targets for that event, and invokes the appropriate action for that target for that event.

mritunjayonemail commented 12 years ago

Hi Dale,

As suggested by you, i added the UITextField+DFX.h and UITextField+DFX in our Xcode project. From victor we are successfully able to call the DFX_setText method. But problem is still it is not calling the listener.

In our code the event is registered as:

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(textFieldDidChange:) name:@"UITextFieldTextDidChangeNotification" object:nil];

and method 'DFX_replaceTextAtLocation' in UITextField+DFX method is

But it is not executing properly and it is giving exception. Actually it is not able to find the text field on which 'DFX_setText' is called and hence goes into infinite loop.

When we comment

[[NSNotificationCenter defaultCenter] postNotificationName:@" UITextFieldTextDidChangeNotification" object:UITextFieldTextDidBeginEditingNotification]; in 'DFX_replaceTextAtLocation' method, it sets the value of text field but does not call the listener.

Kindly suggest what we are missing here.

Regards, Mritunjay

On Mon, May 21, 2012 at 3:30 AM, Dale Emery < reply@reply.github.com

wrote:

Also, I want to offer a slight distinction in your terminology (a distinction I myself discovered only yesterday): In order to simulate the UIControlEventEditingChanged event, you don't "send a notification to the observer," you "invoke the action on the target." These are very similar ideas in the abstract, but the Objective-C mechanisms are quite different.

The "notifications and observers" mechanism is handled by an application-wide singleton NSNotificationCenter. Observers register with the notification center, and publishers call NSNotificationCenter methods to publish notifications. The singleton NSNotificationCenter maintains the list of observers, what notifications they've subscribed to, and what message to send to each observer.

On the other hand, "control events" are handled entirely by UIControl objects. "Targets" register for events by making connections in the nib (or manually in the code). The control itself maintains the list of targets, what events they've registered for, and the "action" to invoke when the event fires. Then at the appropriate time, the control (or some iOS thing) tells the control to "send the actions" for some control event. The control looks up its own private list of targets for that event, and invokes the appropriate action for that target for that event.


Reply to this email directly or view it on GitHub: https://github.com/dhemery/victor/issues/9#issuecomment-5812716

Regards, Mritunjay

dhemery commented 12 years ago

It might be good to switch to Skype to sort out the details. If you see me logged in (dalehemery) ping me with a text message to see if I'm available for a call.

dhemery commented 12 years ago

This line looks like an error:

[[NSNotificationCenter defaultCenter] postNotificationName:@"UITextFieldTextDidChangeNotification"
                                                    object:UITextFieldTextDidBeginEditingNotification];

The object parameter should be self (the text field itself), like this:

[[NSNotificationCenter defaultCenter] postNotificationName:@"UITextFieldTextDidChangeNotification"
                                                    object:self];
mritunjayonemail commented 12 years ago

Hi Dale,

Actually we tried that one also i.e.

[[NSNotificationCenter defaultCenter] postNotificationName:@ "UITextFieldTextDidChangeNotification" object:self];

But that also ends with same error.

Today i left MAC in office. Tomorrow i will ping u on skype when i have mac with me.

Regards, Mritunjay

On Mon, May 21, 2012 at 11:35 PM, Dale Emery < reply@reply.github.com

wrote:

This line looks like an error: [[NSNotificationCenter defaultCenter] postNotificationName:@ "UITextFieldTextDidChangeNotification"

object:UITextFieldTextDidBeginEditingNotification];

The object parameter should be self (the text field itself), like this: [[NSNotificationCenter defaultCenter] postNotificationName:@ "UITextFieldTextDidChangeNotification" object:self];


Reply to this email directly or view it on GitHub: https://github.com/dhemery/victor/issues/9#issuecomment-5829394

Regards, Mritunjay

mritunjayonemail commented 12 years ago

Hi Dale,

Thanks for your help. Now listener is getting called properly on 'setText' method. There was some problem in code in our side, that's why listener was not getting called.

I am really thankful to you for proactively looking in the issue. While working on this issue i developed interest in Victor/Frankify. Can you please point me to some document which will give some more insights into functioning of Victor/Frank i.e how it works etc.

Regards, Mritunjay

On Mon, May 21, 2012 at 11:48 PM, Mritunjay Kumar < mritunjayonemail@gmail.com> wrote:

Hi Dale,

Actually we tried that one also i.e.

[[NSNotificationCenter defaultCenter] postNotificationName:@ "UITextFieldTextDidChangeNotification" object:self];

But that also ends with same error.

Today i left MAC in office. Tomorrow i will ping u on skype when i have mac with me.

Regards, Mritunjay

On Mon, May 21, 2012 at 11:35 PM, Dale Emery < reply@reply.github.com

wrote:

This line looks like an error: [[NSNotificationCenter defaultCenter] postNotificationName:@ "UITextFieldTextDidChangeNotification"

object:UITextFieldTextDidBeginEditingNotification];

The object parameter should be self (the text field itself), like this: [[NSNotificationCenter defaultCenter] postNotificationName:@ "UITextFieldTextDidChangeNotification" object:self];


Reply to this email directly or view it on GitHub: https://github.com/dhemery/victor/issues/9#issuecomment-5829394

Regards, Mritunjay

Regards, Mritunjay