WatchOS 7.1 WKLongPressGesture detected, alert presented, but action closures not firing - xcode

I am trying to implement a WKLongPressGestureRecognizer in my app. The long press gesture is recognized and the alert it presented. However, when I select the option to clear the table (I'm using Realm), the alert controller is dismissed, but the take is not cleared. When I tried to debug by adding breakpoints in the code, it seemed that the code inside the closure was being skipped completely. Any idea what I'm missing? (Should I be using an action sheet sided of an alert sheet?) I've tried so many different things. Here's the code with the print statements that I've been using to debug. None of the print statements inside the closures are currently being triggered.
#IBAction func handleLongPress(_ sender: Any) {
print("long press pressed")
WKInterfaceDevice.current().play(.click)
let clearAction = WKAlertAction(title: "Clear", style: .destructive) {
print("clear button pressed")
}
let cancelAction = WKAlertAction(title: "Cancel", style: .default) {
print("cancel button pressed")
}
presentAlert(withTitle: "Are you sure?", message: "Action cannot be undone", preferredStyle: .alert, actions: [clearAction, cancelAction])
print("exiting long press")}
Thanks for any input or advice.

The gesture recognizer will call selector handleLongPress twice, once with state == began, and once with state cancelled. I found that this causes the problems with presentAlert that you're describing.
Try checking for the began state:
#IBAction func handleLongPress(_ sender: WKGestureRecognizer) {
guard sender.state == .began else {
return
}
// rest of handleLongPress implementation goes here
}
This should ensure your alert is presented exactly once.

Related

TouchId and FaceId authorization conditions

I need the authentication via TouchID and FaceID and various "else" requests in my app. I managed to integrate it, so that after pressing the "button" to proceed, you move on to another VIEW.
The problem is that if the "cancel" item is pressed, however, the button that is connected to the next VIEW continues to work. I would like if the user presses "cancel" it will be shown on the home page. The Button is connected via Main.Storyboard to the second VIEW Controller created.
Below is the part of the code I wrote:
#IBAction func touchID(_ sender: Any){
let context:LAContext = LAContext()
if context.canEvaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, error: nil)
{
context.evaluatePolicy(LAPolicy.deviceOwnerAuthenticationWithBiometrics, localizedReason: "Autorization Required", reply: { (wasSuccessful, error) in
if wasSuccessful {
print("Correct")
//let vc = self.storyboard?.instantiateViewController(withIdentifier: "SecondViewControllerID") as! SecondViewController
//self.present(vc, animated: true, completion: nil)
}
else
{
print("Incorrect")
}
})
}else{
print("TouchID/Facec ID not configured")
}
}
}
I am a beginner.
Try to do this:
Your "button" to proceed must call to your TouchID function. When you print "correct", you must create the navigation by code. If you print "Incorrect", dont create the navigation.
If you print "TouchID/Face ID not configured", you should show an alertview and maybe open the app settings configuration to enable/disable touch/faceId.

IQKeyboardManager unexpected behavior

i have a simple chat view that contain table view, text field and a send button
i'm using IQKeyboardManager to handle keyboard appearance but the unexpected behavior is that when i click on send button the keyboard disappear that behavior don't happen on chat apps like whatsApp the keyboard remain appear'
how to handle this behavior to be like whatsApp
Update : here is the send button code
#IBAction func sendPressed(_ sender: AnyObject) {
//TODO: Send the message to Firebase and save it in our database
if (messageTextfield.text?.isEmpty)!{
showAlert(alertTitle: "", alertMessage: "can't send empty Message", actionTiltle: "Ok")
}
else{
messageTextfield.isEnabled=false
sendButton.isEnabled=false
let messageDB=Database.database().reference().child("Messages")
let dictionary:[String:String]=["Sender":(Auth.auth().currentUser?.email)!,"MessageBody":messageTextfield.text!]
messageDB.childByAutoId().setValue(dictionary)
messageTextfield.text=""
messageTextfield.isEnabled=true
sendButton.isEnabled=true
}
}
The issue is with isEnable property used isUserInteration property instead of that
#IBAction func sendPressed(_ sender: AnyObject) {
//TODO: Send the message to Firebase and save it in our database
if (messageTextfield.text?.isEmpty)!{
showAlert(alertTitle: "", alertMessage: "can't send empty Message", actionTiltle: "Ok")
}
else{
messageTextfield.isUserInteractionEnabled=false
sendButton.isUserInteractionEnabled=false
let messageDB=Database.database().reference().child("Messages")
let dictionary:[String:String]=["Sender":(Auth.auth().currentUser?.email)!,"MessageBody":messageTextfield.text!]
messageDB.childByAutoId().setValue(dictionary)
messageTextfield.text=""
messageTextfield.isUserInteractionEnabled=true
sendButton.isUserInteractionEnabled=true
}
}

Mac NSTextField won't resign firstResponder

I have a window with some NSTextFields. When I click in one and edit the value and press return, I want the focus to go back to what it was before. I don't want the blue ring around the text field and I don't want further keystrokes going to that text field. I would have thought this would happen automatically.
I tried these, and none of them work
sender.resignFirstResponder()
sender.window?.makeFirstResponder(nil)
InspectorWindowController.window?.makeFirstResponder(nil)
AnotherWindowController.window?.becomeFirstResponder()
I'm doing these at the end of my IBAction associated with the text field. Maybe I have to do it from somewhere else?
Thanks
I figured this out. I guess the sent action is happening on another thread. So you have to call makeFirstResponder using Dispatch async.
DispatchQueue.main.async { //omg
sender.window?.makeFirstResponder(nil)
}
I needed to dismiss first responder in my SwiftUI macOS app and here what I found working in a way I need:
func controlTextDidEndEditing(_ obj: Notification) {
DispatchQueue.main.async {
guard let window = self.textField.window else {
return
}
// https://stackoverflow.com/questions/5999148/how-to-determine-whether-an-nssearchfield-nstextfield-has-input-focus
// We need to make sure that our text field is still first responder.
guard let textView = window.firstResponder as? NSTextView,
textView.delegate === self.textField else {
return
}
window.makeFirstResponder(nil)
}
}

Xcode UI test - UI Testing Failure - Failed to scroll to visible (by AX action) when tap on Search field "Cancel' button

I am trying to dismiss the search field by tapping 'Cancel' button in search bar.
The test case is failing to find the cancel button. It was working fine in Xcode 7.0.1
I have added predicate to wait for button to appear. The test case is failing when we tap of "cancel" button
let button = app.buttons[“Cancel”]
let existsPredicate = NSPredicate(format: "exists == 1")
expectationForPredicate(existsPredicate, evaluatedWithObject: button, handler: nil)
waitForExpectationsWithTimeout(5, handler: nil)
button.tap() // Failing here
logs:
t = 7.21s Tap SearchField
t = 7.21s Wait for app to idle
t = 7.29s Find the SearchField
t = 7.29s Snapshot accessibility hierarchy for com.test.mail
t = 7.49s Find: Descendants matching type SearchField
t = 7.49s Find: Element at index 0
t = 7.49s Wait for app to idle
t = 7.55s Synthesize event
t = 7.84s Wait for app to idle
t = 8.97s Type 'vinayak#xmd.net' into
t = 8.97s Wait for app to idle
t = 9.03s Find the "Search" SearchField
t = 9.03s Snapshot accessibility hierarchy for com.test.mail
t = 9.35s Find: Descendants matching type SearchField
t = 9.35s Find: Element at index 0
t = 9.36s Wait for app to idle
t = 9.42s Synthesize event
t = 10.37s Wait for app to idle
t = 10.44s Check predicate `exists == 1` against object `"Cancel" Button`
t = 10.44s Snapshot accessibility hierarchy for com.test.mail
t = 10.58s Find: Descendants matching type Button
t = 10.58s Find: Elements matching predicate '"Cancel" IN identifiers'
t = 10.58s Tap "Cancel" Button
t = 10.58s Wait for app to idle
t = 10.64s Find the "Cancel" Button
t = 10.64s Snapshot accessibility hierarchy for com.test.mail
t = 10.78s Find: Descendants matching type Button
t = 10.78s Find: Elements matching predicate '"Cancel" IN identifiers'
t = 10.79s Wait for app to idle
t = 11.08s Synthesize event
t = 11.13s Scroll element to visible
t = 11.14s Assertion Failure: UI Testing Failure - Failed to scroll to visible (by AX action) Button 0x7f7fcaebde40: traits: 8589934593, {{353.0, 26.0}, {53.0, 30.0}}, label: 'Cancel', error: Error -25204 performing AXAction 2003
I guess here "Cancel" button returns false for hittable property, that is preventing it from tapping.
If you see tap() in documentation it says
/*!
* Sends a tap event to a hittable point computed for the element.
*/
- (void)tap;
It seems things are broken with Xcode 7.1. To keep myself (and you too ;)) unblocked from these issues I wrote an extension on XCUIElement that allows tap on an element even if it is not hittable. Following can help you.
/*Sends a tap event to a hittable/unhittable element.*/
extension XCUIElement {
func forceTapElement() {
if self.hittable {
self.tap()
}
else {
let coordinate: XCUICoordinate = self.coordinateWithNormalizedOffset(CGVectorMake(0.0, 0.0))
coordinate.tap()
}
}
}
Now you can call as
button.forceTapElement()
Update - For Swift 3 use the following:
extension XCUIElement {
func forceTapElement() {
if self.isHittable {
self.tap()
}
else {
let coordinate: XCUICoordinate = self.coordinate(withNormalizedOffset: CGVector(dx:0.0, dy:0.0))
coordinate.tap()
}
}
}
For me, the root cause was that the objects I wanted to tap
have been set to hidden (and back)
have been removed and re-attached
In both cases the isAccessibilityElement property was false afterwards. Setting it back to true fixed it.
This question ranks well for Google queries around the term "Failed to scroll to visible (by AX action) Button". Given the age of the question I was inclined to think this was no longer an issue with the XCUITest framework as the accepted answer suggests.
I found this issue was due to the XCElement existing, but being hidden behind the software keyboard. The error is emitted by the framework since it is unable to scroll a view that exists into view to be tappable. In my case the button in question was behind the software keyboard sometimes.
I found the iOS Simulator's software keyboard may be toggled off in some cases (eg: on your machine) and toggled on in others (eg: on your CI). In my case I had toggled the software keyboard off on one machine, and by default it was toggled on on others.
Solution: Dismiss the keyboard before attempting to tap buttons that may be behind it.
I found tapping somewhere that explicitly dismissed the keyboard before tapping on the button solved my problem in all environments.
I added add some actions to get the current responder to resignFirstResponder. The views behind my text views will force the first responder to resign, so I tap somewhere just underneath the last text area.
/// The keyboard may be up, dismiss it by tapping just below the password field
let pointBelowPassword = passwordSecureTextField.coordinate(withNormalizedOffset: CGVector(dx: 0.5, dy: 1))
pointBelowPassword.press(forDuration: 0.1)
The workaround of Sandy seemed help for a while but then no more - I then changed it like this:
func waitAndForceTap(timeout: UInt32 = 5000) {
XCTAssert(waitForElement(timeout: timeout))
coordinate(withNormalizedOffset: CGVector(dx:0.5, dy:0.5)).tap()
}
Main point being that as the issue is that isHittable check throws an exception, I don't do this check at all and go straight for coordinates after the element is found.
Please check the trait of the element, i was facing the same issue with TableViewSectionHeader, i was trying to tap but it was failing at every point
Try this:
if !button.isHittable {
let coordinate: XCUICoordinate = button.coordinate(withNormalizedOffset: CGVector(dx:0.0, dy:0.0))
coordinate.tap()
}
In my case it was having a programmatically added UI element covering the button.
If you're using the AppCenter simulator to run the tests, you should make sure that you're running the tests on the same device version than your local simulator. I lost 3 days of work because of this.
In the spirit of things that can cover your element, I had the RN debugger partially overlayed on top of my icon:
I had this issue because I set a toolbar (and ToolbarItem) on a GeometryReader:
GeometryReader { proxy in
ZStack { ... }
}
.toolbar {
ToolbarItem(placement: .navigationBarTrailing) {
Button(action: { ... }) {
Text(Localizable.Global.login.localized)
}
.accessibilityIdentifier("welcomeViewLoginButton")
}
}
After setting the toolbar on the ZStack instead, the toolbar item button was hittable again.
GeometryReader { proxy in
ZStack {
...
}
.toolbar {
ToolbarItem(placement: .navigationBarTrailing) {
Button(action: { ... }) {
Text(Localizable.Global.login.localized)
}
.accessibilityIdentifier("welcomeViewLoginButton")
}
}
}

Opening NSSavePanel as sheet

I am using XCode7 beta2 to play around with Swift 2. Trying to use a File-Selection Dialog (NSSavePanel) brought me into some trouble.
Running the following code by clicking the associated button won't bring up the dialog as a sheet (not at all) but make my window's decoration disappear, leaving it in a broken state where otherwise functional sheets open as dialogs without decoration. Using the call to the deprecated API beginSheetModalForWindow, like in the commented line, works like expected.
#IBAction func openFileClicked(sender: AnyObject) {
let openPanel = NSSavePanel()
openPanel.canCreateDirectories = true
//openPanel.beginSheetModalForWindow(self.view.window!, completionHandler: {
openPanel.beginSheet(self.view.window!, completionHandler: {
(result) -> Void in
print("opening:\(result)" )
})
}
Is my code broken somehow or is there a issue with the API I am calling.

Resources