Detecting swipes on all four directions on WatchKit using the Storyboard - swift

I am trying to detect the swipes on the AppleWatch on all four directions. Yet I am not clear how to assign many values to the direction of the WKSwipeGestureRecognizer I inserted in the Storyboard. I tried with:
swiper.direction = [.right , .left , .up , .down]
that was funnily accepted by the compiler, differently of using the bitwise |, but, using this configuration, function:
#IBAction func swipe(_ sender: Any) {
switch swiper.direction {
case WKSwipeGestureRecognizerDirection.right:
print("Swiped right")
case WKSwipeGestureRecognizerDirection.down:
print("Swiped down")
case WKSwipeGestureRecognizerDirection.left:
print("Swiped left")
case WKSwipeGestureRecognizerDirection.up:
print("Swiped up")
default:
break
}
}
is very seldom called and when it is the swiper.direction is invariably .right.
Apple is very cryptic at:
https://developer.apple.com/reference/watchkit/wkswipegesturerecognizer/1650828-direction
by saying:
"The default value of this property is right. You may specify more
than one direction to track swipes in multiple directions with the
same gesture recognizer."
without revealing how.

At any rate, totally ignoring what Apple says, putting four WKSwipeGestureRecognizer in the storyboard each with a different direction and target does the job.

1) Select WKSwipeGestureRecognizer from Utilities box on the right side
2) From the attributes inspectors, check "Delays touches began" and select "Swipe" type that you need
-
3) Ctrl + drag IBAction to your viewController and implement function

Related

How can I limit a text field to only intaking Double values

So essentially I'm creating a calculator type app, in which I only want to intake numbers, decimals, and the negative sign. I'm fairly new to Xcode and swift so I wouldn't consider my knowledge extensive when it comes to knowing how to handle these sorts of issues.
Here is my current attempt at a solution
let v = Double(inputOne.text!)!
(inputOne. is the associated text field)
This works well in my algorithm when everything is inputted as it should be, however when inputting anything other than a valid double I receive "Fatal error: Unexpectedly found nil while unwrapping an Optional value", and the app crashes.
I figured someone may have already come up with a creative solution to this problem or that there may be some command in Xcode that limits text fields in this way, however I am new to Xcode and unaware of such things if they exist. Maybe there is some way I can implement an error message that occurs whenever something other than a valid double is inputted without crashing the app? Any creative solutions would be appreciated.
You can use a UITextView as your input field (if you want a one-line input, use a textField). Then, simply set your ViewController as the textView's delegate -inside your ViewController add the following line (and don't forget to inherit UITextViewDelegate):
textView.delegate = self
Essentially, what this does is allow the ViewController to take ownership of some of the textView's functionalities. In this case, we are interested in filtering the user input and for that you can use the following function:
/// Intercept whatever character the user is typing on the keyboard
func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
// If the user presses "enter", handle it the way you want
guard text.rangeOfCharacter(from: CharacterSet.newlines) == nil else {
// Handle new line
}
// If character is a digit, a dot, or a dash, allow input, else reject it.
if text == "-" || text.rangeOfCharacter(from: CharacterSet.decimalDigits) != nil || text == "." {
return true
} else {
return false
}
}

Detect active NSSplitViewItem

I have a SplitView with (several) SplitViewItems. Echt SplitViewItem has a ViewController with multiple views in it.
I need to detect which of the SplitViewItems has the focus of the user.
For example: if the user clicks on any control/view (or navigates to it in any other way), the background of the SplitViewItem that contains that view item should change. As I do not know which/how many views will be enclosed in the ViewController in the SplitViewItem, I'd prefer to detect which SplitViewItem is the 'active' one in the SplitViewController.
I have been searching for a solution all day long. I could not find any kind of notification, nor found a way to solve this managing the responder chain.
Can anybody please point me in the right direction? A (swift) code example would be highly appreciated.
Thanks!
It took me quite some research, but I found a working solution. Not the most elegant, but working.
I found the best approach to be to add an event monitor to the SplitViewController.
In viewDidLoad() add the following code:
NSEvent.addLocalMonitorForEvents(matching: [.keyDown, .leftMouseDown, .flagsChanged]) { [unowned self] (theEvent) -> NSEvent? in
let eventLocation = theEvent.locationInWindow
let numberOfSplitViews = self.splitViewItems.count
var activeIndex: Int?
for index in 0..<numberOfSplitViews {
let view = self.splitViewItems[index].viewController.view
let locationInView = view.convert(eventLocation, from: nil)
if ((locationInView.x > 0) && (locationInView.x < view.bounds.maxX) && (locationInView.y > 0) && (locationInView.y < view.bounds.maxY)) {
activeIndex = index
break
}
}
switch theEvent.type {
case .keyDown:
print("key down in pane \(activeIndex)")
self.keyDown(with: theEvent)
case .leftMouseDown, .rightMouseDown:
print("mouse down in pane \(activeIndex)")
self.mouseDown(with: theEvent)
case .flagsChanged:
print("flags changed in pane \(activeIndex)")
self.flagsChanged(with: theEvent)
default:
print("captured some unhandled event in pane \(activeIndex)")
}
return theEvent
}
(you may have to tweak the relevant events to your own liking. Also, you may need to remover the monitor using NSEvent.removeMonitor(_:)).
In addition (out of scope of this question), you might also want to consider making the variable activeIndex an observable class variable (I did this using RxSwift), allowing you to easily react on any change happening inside the 'active pane'.
Any more elegant/simple solutions are welcome!

Should I use a For - in loop in swift to set field value

I have created an app with a codeable array in Swift. I have a boolean field to show which item in my list is the active record. If I choose another item in my list to make active (true) I would like to mark all other records as false. I was wondering if using a for-in loop would be the proper way to do this?
I have this code to activate the button but have been told that is not the proper way to do it.
#IBAction func activateButtonTapped(_ sender: UIButton) {
activateButton.isSelected = !activateButton.isSelected
updateSaveButtonState()
}
Any suggestions would be appreciated.
A for-loop would be the most naive (simple) way to do this, but not the most performant as the number of button increases (you're bound by O(n) time).
If one and only one button can be active at a time then you're better off using another variable to reference the currently active button. Your code would instead look like this:
private weak var activeButton: UIButton?
#IBAction func activateButtonTapped(_ sender: UIButton) {
activeButton?.isSelected = false
sender.isSelected = true
activeButton = sender
}
This ensures O(1) time.
If you want multiple buttons active at once, you can use an array of active buttons, which you'd loop over to deactivate. In that case, you still have a worst case O(n) time complexity, but you're almost always going to be looping over a smaller subset of the buttons.
Yes, a for in loop would be perfect for this. You could set all the buttons selection status to false and then set the one you just activated to true.
for button in buttons {
button.isSelected = false
}
activateButton.isSelected = true
Or you could check in the loop if the button being tapped is the one that in the loop.
for button in buttons {
button.isSelected = button == activateButton
}

What is the actual meaning of " ! " prefix in Swift?

I want to know about prefix !. I have created an app, and it has tableView. And I have used setEditing:animated property for editing a tableView, it allows multiple selection. When user start selecting? We need to cancel segue operations. Of course we need to override shouldPerformSegueWithIdentifier method. Here's my code
override func shouldPerformSegueWithIdentifier(identifier: String, sender: AnyObject?) -> Bool {
return !editing
}
Firstly I've tried to use return editing. Xcode does not gave me any errors even run time errors. Everything seems to works just fine. But segues are still works. And then I've tried to use with prefix return !editing. Works perfect! What's the actual meaning of this prefix ! ?
Thanks
The ! operator is the logical NOT of a boolean value; i.e. !true becomes false, !false becomes true.

Unit testing for IBAction connection with good form

I've created a successful unit test that checks for an IBAction in Swift. However, the form isn't great:
func testAddButtonIBActionShouldExist() {
let actions=viewController.addButton.actionsForTarget(viewController, forControlEvent: UIControlEvents.TouchUpInside)
XCTAssertNotNil(actions, "Add button should have conections")
if actions != nil{
let actionsAsNSArray:NSArray=actions! as NSArray
XCTAssertTrue(actionsAsNSArray.containsObject("addNumbers:"), "Add button not connected to correct IBAction")
}
}
It separates the test for nil and the containsObject into two separate parts, and also includes an if… both of which I believe are bad unit testing form. Is there a way to somehow combine these in Swift 1.2 (or Swift 2)? Thanks for reading.