How does one tell a button to make sender something else? - ios

A quote from Apple docs: "The sender parameter usually identifies the control sending the action message (although it can be another object substituted by the actual sender)."
How is this accomplished? The "it can be another object" part.
In my case I have a number of buttons that all target the same method which produces a popover with a graphic of a tape measure with a pointer to the number. I have a lot of labels I want to use this on and will put a small button with an icon next to each of them so the user can see the fractional equivalent. I need a way to tell the method the number, which is held by a different label in each case. Making "sender" the label would make this a simple thing.

You can pass any sender you want if you invoke the method from somewhere else in your code, but if your action method is being invoked from an action on the control, then the sender will be the control (i.e. UIButton) that invoked the method. You will need to associate the sensor with the meaning in your code. The tag property may be of use.
The quote you added from Apple is merely indicating that the actual sender can supply a different object if it wants to - but it doesn't mean that all objects have the ability to specify a different sender. In the case of a UIButton there is no way of specifying a different sender.

Related

XCUIElement - Obtain Image value

I have an variable that's of type .Image and class XCUIElement. Something like this:
var image = app.descendantsMatchingType(.Image).elementAtIndex(0)
Is there a way I can extract the actual image so I can compare it to another image?
I've tried caling the value method, but it returns a string. Casting it to a UIImage always fails.
I have had a conversation about this with the Apple Developer Tools evangelist recently. There is currently no way of accessing the actual image from an image view, button, etc. Similarly, there is no way to access other properties of views that might be of interest, like "isHidden" or "attributedText", etc. I was told that the engineers on the UI Testing team are interested in the use cases that people are wanting access to these properties for, so it would be very helpful -- both for them and for the other people who want this feature -- if you would file a bug report / feature request asking for it at https://bugreport.apple.com
As a tip regarding the "value" property on an XCUIElement, at least for now this appears to map to the "accessibilityValue" property of whatever view the XCUIElement is referencing. So if you set that accessibilityValue of a view you are interested in to contain some information you are interested in verifying, then this can possibly help in testing. Two things to be aware of though:
1) Even though the "value" property of an XCUIElement is of type "id", the type of the accessibilityValue property is "NSString". I don't know what would happen if you try to force some non-string value (like an image) into accessibilityValue and then try to retrieve it from the "value" property of XCUIElement, but I suspect it wouldn't work well. Partially because:
2) The accessibilityValue property of a view is actually used by Apple's VoiceOver feature for the vision impaired. When the value is set, it will be read out loud when the user taps on that element (which is why it's supposed to be a string).
I also covered the issue with not being able to access properties of view via XCUIElement in more detail here: http://www.danielhall.io/exploring-the-new-ui-testing-features-of-xcode-7
I know it may be not exactly what you're looking for, but I managed to write a test that checks if the visual representation of a UIImage on the screen has changed.
I'm using a screenshot() method of XCUIElement which returns an instance of XCUIScreenshot:
let myImage = XCUIApplication().images["myAccessibilityIdentifier"]
let screenshotBefore = myImage.screenshot()
//...
//do some actions that change the image being displayed
//...
let screenshotAfter = myImage.screenshot()
//Validating that the image changed as intended
XCTAssertNotEqual(screenshotBefore.pngRepresentation, screenshotAfter.pngRepresentation)
The screenshots will be the size of the image as rendered on the screen which may be different to the original image of course.
It's important to compare the PNG representations using the pngRepresentation property, but not the XCUIScreenshot objects because the two objects will always be different internally.
This technique can't test that the image displayed on the screen is exactly what is needed but at least can detect changes in the image.

What does connect action do in iOS development?

I am writing code for a tip calculator in Xcode using swift. I am reading a book and was instructed to connect the slider to the calculateTip method. I am trying to figure out what connecting the action will do. Does this simply mean that every time the slider is moved the calculateTip method will be called?
This particular connection means that you assign an action to the slider: In this case your calculateTip method. By default the slider sends a message to this method, when its value has changed. This connection can also be done programmatically, but Xcode makes that easier for you.
So to answer your question: yes. Anytime the slider is moved the calculateTip method is called. But take a look on the sliders continuousproperty to decide whether this method should be called when the user stops dragging the slider, or — as the name suggests — to send continuous messages.
Yes, it depends which action you choose exactly, but if you select the ValueChanged action then yes, it will call that method every time the slider moves.

What is the difference between the arguments 'sender' and 'none' for an IBAction in iOS

While creating a new IBAction Method, I have dragged from the Button in the storyboard to my header file as I should. The Popup that appears I have noticed has an arguments dropdown which offers 3 options which are none, sender and sender and event. What is the difference between 'none' and 'sender' and in what situations would each be used?
None
You don't need to know any information about what triggered the action, just that the action was triggered.
Sender
You not only need to know that an action was triggered, but information about what object triggered the action. For instance, if you need to know which button triggered a certain action in order to change its properties.
Sender and event
You need to know the action was triggered, what object triggered this action, and the type of event that triggered the action. For example, if you need to know which button triggered a certain action in order to change its properties, and you will change them differently if they touch down on the button vs touch up vs double-tap vs etc. but you don't want to create a separate action method for each type of event.
Stonz2's answer covers it pretty well.
Some examples where you might want the sender:
Say you have a calculator app, and you have digit buttons and operator buttons. Rather than writing a different IBAction method for every button, you might write a -digitTapped action and an -operatorTapped action.
You could add tag values to each button, and then in your action method, interrogate the sender to see what it's tag is.
Another example would be a slider. You might use the sender parameter to get a pointer to the slider and fetch it's value.
(BTW, by default IB makes the type of the sender be id, which is an anonymous pointer. I usually change the type to be the type of the object that is triggering the action, like UIButton, UISlider, etc.)

Invoking button action in Unit Test in Xcode

I am trying to write a unit test case for calculator in Xcode, currently I am writing test case for the add function.
This is my digit pressed function:
- (IBAction)digitPressed:(UIButton *)sender.
I have seen an example where if the method name is
- (IBAction)digitPressed:(id)sender,
you can invoke the function with help of view tag like
[calc_view_controller digitPressed:[calc_view viewWithTag:6];
The instance defined above in implementation section as
app_delegate = [[UIApplication sharedApplication] delegate];
calc_view_controller = app_delegate.viewController;
calc_view = calc_view_controller.view;
now since my button type is (UIButton *) I cant use view tag, is there any other alternative for UIButton type?
If so, Can you give me an example?
A button is a view, so -viewWithTag: will find it just fine. The only issue is your sender type not agreeing with the type returned by -viewWithTag:, but you can solve that with a cast if you're sure the view you'll get back is a button, or you can check first:
[calc_view digitPressed:(UIButton*)[calc_view viewWithTag:6]];
or:
UIButton *button = (UIButton*)[calc_view viewWithTag:6]];
if ([button isKindOfClass:[UIButton class]]) {
[calc_view digitPressed:button];
}
Either works in practice; the latter is safer and makes it easy to add an additional test: you could fail the test if the button isn't a UIButton.
You do it in the bad way, you shouldn't compare sender.titleLabel.text. Think about what happens when you'll change the label text, because e.g you must ship your app in another language.
But if you still want to handle button recognizing in that way, you have to create UIButton in your unit test and set it the proper label text value.
Rather than invoking the IBAction method, I would invoke the specific method which peforms the addition.
There are a number of things that you could test here, for example:
The UIButton object sends the correct value to the digitPressed method
The digitPressed method correctly extracts the value from the UIButton object and passes this value to the add method
The result of the add method is what you expect
How much you test is up to you, personally I wouldn't get too hung up on 1 and 2. If the logic is wrong in either of these it will become obvious, and they are unlikely to attract regressions.
To me it is more important to fully test the add method. Send in plenty of common cases, edge cases and boundary values, rather than worrying about the flow from the UIButton press.

Access first responder of MFMessageComposeViewController

I'm interested in doing something similar to this, however the component subviews of MFMessageComposeViewController are a much different than MFMailComposeViewController.
I figured out how to set focus to the input that let's you to type your message text by simply calling setRecipients: with an array containing a blank NSString. However, I'd like to paste non-text from the pasteBoard into the input, so I can't simply use setBody:.
Problem:
What I need to do is get a reference to the actual text field that is the current first responder for my MFMessageComposeViewController. This way, I have a "sender" I can pass to UIPasteboard's paste: method. The problem is, I can't seem to walk the subview hierarchy the same way as MFMailComposeViewController, so I can't find out which view is first responder.
I've even tried this, but the view is always returned as nil if I do a [myMessageVC.view findFirstResponder]
Word of caution, you're not supposed to have your hands inside that view. Apple will refuse your app for doing so. You are only allowed to set the body and recipients.
Important The message composition interface itself is not customizable
and must not be modified by your application. In addition, after
presenting the interface, your application is unable to make further
changes to the SMS content. The user can edit the content using the
interface, but programmatic changes are ignored. Thus, you must set
the values of content fields, if desired, before presenting the
interface
http://developer.apple.com/library/ios/#documentation/MessageUI/Reference/MFMessageComposeViewController_class/Reference/Reference.html

Resources