Miscellaneous2 Flashcards
How is your app notified during a touch interaction when a call comes through?
UIKit notifies the app via touchesCancelled(_:with:)
Explain how UITouch class in UIKit works when a user adds one finger then another?
A UITouch object is created for the first finger and delivered to the app via a UIEvent object to the UIView’s touchesBegan, touchesMoved, touchesEnded method calls.
That is repeated for each subsequent touch interaction with a new finger, with multiple touches delivered together inside the UIEvent object.
Can you override functions from a Swift extension?
No, not permitted. Only permitted to override from a class that inherits from the class you are extending.
What is the importance of the final keyword for classes and methods?
A final class cannot be extended. Final methods cannot be overridden in subclasses.
How can you keep track of multi-finger touches?
Override touchesBegan, touchesMoved, touchesEnded, touchesCancelled in the UIView or UIViewController class while tracking the touches in an array of 5 UITouch objects, each indexed by finger.
https://stackoverflow.com/questions/39823914/how-to-track-multiple-touches
var fingers = UITouch?
// SETUP ARRAY IF FINGER NIL override func touchesBegan(_ touches: Set, with event: UIEvent?) { super.touchesBegan(touches, with: event) for touch in touches{ let point = touch.location(in: self.view) for (index,finger) in fingers.enumerated() { if finger == nil { fingers[index] = touch print("finger \(index+1): x=\(point.x) , y=\(point.y)") break } } } }
//TRACK MOVEMENT BY FINGER MATCHING TOUCH ID override func touchesMoved(_ touches: Set, with event: UIEvent?) { super.touchesMoved(touches, with: event) for touch in touches { let point = touch.location(in: self.view) for (index,finger) in fingers.enumerated() { if let finger = finger, finger == touch { print("finger \(index+1): x=\(point.x) , y=\(point.y)") break } } } }
Can touchesBegan, touchesMoved, touchesEnded, touchesCancelled be overridden on UIViews and ViewControllers?
Yes
What are some ways of restricting touches on a UIView/ViewController?
Universally: UIApplication’s beginIgnoringInteractionEvents (bookended by endIgnoringInteractionEvents)
isUserInteractionEnabled
alpha = 0.0 (touches fall thru)
isHidden
isMultipleTouchEnabled
How do you convert a point from one coordinate space to another’s?
func convert(_ point: CGPoint, to view: UIView?) -> CGPoint
Where point is in the receiver’s coordinate space and view is the view to translate it into
What are the four methods that intercept touches on UIView and descendants?
touchesBegan, touchesMoved, touchesEnded, touchesCancelled
What is some of the information you can get out of a UITouch?
location(in:): gets the location as translated into the coordinate system of the in parameter element.
previousLocation(in:): same as above, but the the position of the element previously in the coordinate system of the in parameter element
preciseLocation/previousPreciseLocation
timeStamp: TimeInterval can kept as a class variable and used to subtract to get time difference between touches.
force: where 1.0 is average touch
tapCount: number of times the finger was tapped for a given touch.
view: the view to which touches are being delivered, if any
// CODE BELOW: GET PREVIOUS LOCATION, CURRENT LOCATION IN SUPERVIEW AND RECALCULATE THE CENTER BASED ON THE CHANGE IN X/Y override func touchesMoved(_ touches: Set, with event: UIEvent?) {
let t = touches.first let point = self.convert(self.center, to: superview)
if let location = t?.location(in: self.superview), let oldLocation = t?.previousLocation(in: self.superview){
let deltaX = location.x - oldLocation.x let deltaY = location.y - oldLocation.y
self. center.x += deltaX self. center.y += deltaY } }
What class member of UIView can be set to false to stop more than one finger touches?
isMultipleTouchEnabled
Are Gesture Recognizers part of the UIResponder chain?
No, does not participate in responder chain. Touches are delivered to a view and if there are Gesture Recognizers it gets delivered there as well, and to the superview’s Gesture Recognizers, etc. up the chain.
At a high-level how does Gesture Recognizer determine a gesture?
It maintains its own sate as touch events arrive, building up evidence as to what gesture it is, until it decides it has its gesture, where it then sends a single message(e.g., tap) or series of messages(e.g., movement)
What are key methods of UIGestureRecognizer?
location(ofTouch:in) - in, is the view whose coordinate system you want to use
isEnabled: turn on/off
state: progression of modes the GR goes through as it starts, recognizes the gesture, updates changes, and ends. (.possible, .failed, .ended, .began, .changed)
view: view where the GR is attached
List the set of UIGestureRecognizers
UITapGestureRecognizer UIPinchGestureRecognizer UIRotationGestureRecognizer UISwipeGestureRecognizer UIPanGestureRecognizer UIScreenEdgePanGestureRecognizer UILongPressGestureRecognizer
List the states of a UIGestureRecognizer
.possible .failed .ended .began .changed
What do the states of a UIGestureRecognizer mean and at a high-level list out what they do?
UIGestureRecognizers stay in a particular state until a decision is made. State becomes .possible -> .began -> .changed -> .ended for a drag where .changed is called repeatedly. A tap might go .possible->.ended where the gesture is recognized or .possible->.failed where its the wrong gesture.
Action messages are sent to selectors once for .began, as many times as necessary for .changed, and once for .cancelled/.ended.
What methodology do you use to prevent conflicts between UIGestureRecognizers?
require(toFail:UIGestureRecognizer)
Make the UIGestureRecognizers dependent on each other using require to have one fail before the other.
What kind of conflicts can arise between UIGestureRecognizers?
A double tap and a single tap on the same UIView
UIControl in a superclass view (think root window view with UIButton in it and a GR on the view to detect background taps) - If the user taps button the GR will also fire.
Solve this issue with require(toFail:) on the GR
Solve this issue by subclassing UIView and overriding gestureReognizerShouldBegin - this can then return false so the UIView(or Button, or other control) for the type of gesture recognizer, like a SingleTapGR vs others which could return true.
If you subclassed UIView and implemented touchesBegan, touchesMoved, touchesEnded, etc (where touches moved repositions the UIView)
Then, also put a UIPanGestureRecognizer on the UIView inside the UIViewController it’s instantiated in, that only prints to output.
What happens?
UIGestureRecognizers supplant overriding touchesBegan, touchesMoved, etc. but not until the Gesture is recognized.
SO.
Initially, touchesMoved is called until the Gesture is recognized as a Pan by the GR which then takes over. So, the dragging would work until the PanGR takes over, in which case the movement stops and only prints to output.
Difference between isKind(of aClass: AnyClass) and isMember(of aClass: AnyClass)
isKind will return true if the caller is an instance or a subclass of that parameter class. isMember returns true if it is an instance NOT a subclass.
Describe the sequence of events when hitTest method is called by UIView?
hitTest(_ point:CGPoint? with UIEvent?) takes a point in and first calls the same method on its own subviews. The subviews are queried front-to-back order so the one in front reports the hit first.
If a subview returns a view, hitTest immediately returns that view.
If no subviews or all return nil (meaning neither they nor their subview have been hit) then the UIView calls point(inside:with) on itself. If hit was inside itself, the UIView returns self, otherwise nil
If you have two UIViews on superview but want to monitor hit testing at the superview level. You place a UITapGestureRecognizer on the superview and make the UIViews subviews by adding them.
What do you do to distinguish which UIView was tapped?
In the action method of the UITapGestureRecognizer, perform a hit test to return the touched view. Then test if that view is an instance of one or the other UIViews.
let p = tapgr.location(ofTouch:0, in tapgr.view) let v = tapgr.view.hitTest(p, with: nil)
// now we've got the view that was touched, test which one if let v = v as UIView && v === self.myTargetedView{ .... }
What method can you call on a GestureRecognizer that will give you the Point of the touch that occurred?
location(ofTouch:, in UIView)
ofTouch is the Index of the touch event
Can you call hitTest on CALayers?
Normally CALayer do not receive touches. Yet you can still detect touches by calling hitTest on the layer with a point in the super layer coordinates.
Describe what UIViewControllers are responsible for and their purpose?
Logic of what views are shown, what data those views display, response to user gestures, View and Controller in the MVC design pattern,
Manages the interface and presents UIViews
Animation of the interface
Save and restore state
Root View: the UIVC that sits on top of the UIView hierarchy
What retains the root UIViewController?
UIWindow
What retains an embedded UIViewController?
Parent UIViewController
Is it safe to perform dimension dependant calculations from the viewDidLoad method?
No, self.view dimensions may not have been set from this function.
What is the UIViewController’s loadView method for?
Loading the initial view of that UIViewController! (self.view). If you don’t override it, a generic view is assigned to self.view by the default implementation of loadView
How do you use a nib file to load a UIViewController?
Create the nib (file->new file->iOS->user interface -> view. Then instantiate the VC with the name of that nib file:
let theVC = MyRootViewController.init(nibName:"mynib", bundle: nil) self.window.rootViewController = theVC
What are some of the methods that are called when a UIViewController receives events that the main view is being resized?
viewWillTransition(to:with:TransitionCoordinator): sent when main view’s size will change (rotation, user widens window on iPad)
willTransition(to:with:TransitionCoordinator): sent when trait Collection is about to change (could be rotation or other things like dynamic text size change)
traitCollectionDidChange(_:): sent after trait collection changes, when trait collection is set for the first time.
What is the TransitionCoordinator parameter of viewWillTransition/willTransition?
Use the coordinator to hook into the transition animation and perform setup/teardown and add a completion. I.e., change constraints for rotation change.
coordinator.animate(alongsideTransition: { _ in
}) { [unowned self] _ in self.postsCollectionView.reloadData() self.postsCollectionView.collectionViewLayout.invalidateLayout() DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(500)) { // Trigger layoutSubViews call when orientation changes UIView.animate(withDuration: 0.5) { self.postsCollectionView.alpha = 1.0 } } }
What’s the most reliable way to detect size changes (e.g., rotation)?
viewWillLayoutSubviews/viewDidLayoutSubviews: there are some situations where view can be resized without a size change being notified but you’ll ALWAYS get layout events, the viewWillLayoutSubviews and viewDidLayoutSubviews methods.
What’s the updateViewConstraints method?
UIViewController method (that can be overridden) that the view receives when it’s told to update its constraints.
On size change like rotation what are the order of methods related to the change that is called?
willTransition(to:with) //the trait collection viewWillTransition(to:with) //the size updateViewConstraints traitCollectionDidChange(_:) viewWillLayoutSubviews viewDidLayoutSubviews
It’s possible that some of these events are sent more than once so take care to do nothing if nothing is changed.