tvos: UIViewController does not receive touchesBegan - swift

I am trying to write an App for Apple tv4 (tvos). When my App starts, the view controller does receive touchesBegan events, as it should.
Without going into too many details, the App creates, moves, and deletes sub-views to respond to the user's interactions.
After a while, the view controller does not receive touchesBegan any more (this is the strange error that I am trying to debug).
Since I think the problem has something to do with the responder chain, I have made the following two experiments:
If I let the view controller override and return true from canBecomeFirstResponder, then the problem still occurs, but it occurs much less frequently.
If I do not override that function and instead check who is the first respnder, then I find that the App has no first responder, even before the strange error occurs. That is to say, the App has no first responder even when it is working properly!
Questions: What can prevent touchesBegan from being invoked? Is it related to the responder change? If so, please explain 2 above.

How exactly are you supposed to "touch" a view rendered on a non-touch screen enabled TV?
You're not.. tvOS doesn't work like iOS in the way that you cannot detect touches because there is no touch screen enabled input device supported on an Apple TV.
Instead, you use the UIFocusEngine to handle interactions with content presented within your view hierarchy.
Check out "Controlling the User Interface with the Apple TV Remote" from Apple's Developer Library for more information.

Related

Camera turns black upon resume

My app uses multiple features for Apple's demo project AVCam. Everything works just fine except when I exit the app and go back in it, it doesn't show the camera preview anymore. Does anyone know what piece of code I am supposed to use and where it belongs? I tried searching but a lot of questions relating to android popped up.
You need to reinitialize your camera once the App becomes active again. In your app delegate methods, override, applicationDidBecomeActive and send a notification so your view controller knows that your app became active again.
Pending the notification received, you can reload the viewDidLoad, or move the contents of viewDidLoad to viewDidAppear. There's multiple ways to do this. You can also reload the contents of viewDidLoad in viewWillAppear. There's many many many ways to do this, like I said.

Bizarre GameKit behavior. Anyone else seeing this?

I am running Xcode 4.3.3 and am targeting iOS 5.1. I am attempting to include Game Center functionality in a game.
When authenticating the GKLocalPlayer the user is presented with the Sign in to Game Center alert view or shown to be logged in. So far this is all fine, but if the user presses the Create New Account button then any open modal views are moved behind the root view controller and the following error is spit from the console:
Unbalanced calls to begin/end appearance transitions for
<GKModalRootViewController: memory address>.
I have tried moving the GKLocalPlayer authentication code between the app delegate and the root view controller. I have also tried implementing the authentication in a new, blank project. I have tried it with and without Storyboards and ARC. In all of these cases the results were the same: modals hidden behind the root view controller and error given.
Here is the GKLocalPlayer authentication method I am calling from my app delegate’s application:didFinishLaunchingWithOptions: method:
- (void)authenticateLocalPlayer
{
GKLocalPlayer *localPlayer = [GKLocalPlayer localPlayer];
[localPlayer authenticateWithCompletionHandler:^(NSError *error) {
if (localPlayer.isAuthenticated) {
// Perform additional tasks for the authenticated player.
} else {
// Disable Game Center features.
}
if (error) {
// Handle error.
}
}];
}
Here is a screenshot of it. In this picture the root view controller has a background with a 50% alpha value. The modal has been pushed behind the root view controller by this bug.
This stackoverflow question contains the only reference to this error (regarding GKModalRootViewController) I can find, and it doesn't fit since (a.) I’m not using cocos2d. (b.) It happens whether or not I perform a segue, and I am not touching viewWillAppear: or viewDidAppear:. (c.) No acceptable answer was given.
This question and this one seem to involve the same issue (with the view hierarchy being destroyed) but are unanswered and don’t mention the console error message.
Does this happen for anyone else? Any ideas on what could be causing this?
UPDATE 1: I went so far as to put the authentication code into an IBAction connected to a button in the modal view so as to avoid any initialization conflicts. It didn't help.
UPDATE 2: I tried moving the authentication code into a GCD background queue. he results were the same.
Here is the test project (which is GameCenter ready with my app's Bundle ID already entered).
To test:
Log out of Game Center on the test device/simulator (if you are
logged in).
Build and run the app.
Press the info button.
Press Authenticate.
When the Sign in to Game Center alert appears press Create New
Account.
Press Cancel.
Did the “Unbalanced calls...” message appear in the console? Did the
modal view (with the Authenticate button) disappear?
Press the info button.
Did the modal display again?
This bug appears on the list of "bugs Apple fixed in 6.0". I understand you would love a workaround, but when its the APIs you depend on that are buggy, chances of that are slim.
You can however rejoice that 5.x users are slowly dying out.
Best of luck with your app.

What is a UIGobblerGestureRecognizer?

I have just a regular UITableView, and I ran this code:
UITableView *tableView = [[UITableView alloc] init];
for(UIGestureRecognizer *gesture in tableView.gestureRecognizers)
{
NSString *className = NSStringFromClass([gesture class]);
NSLog(#"ClassName:%#", className);
}
One of the output lines is: ClassName:UIGobblerGestureRecognizer
Surprisingly Google has nothing on this. Anyone have any idea what it is?
Most likely this is an internal class that Apple uses. I've come across custom subclasses of UIGestureRecognizers that Apple created for some specific use. I'm sure they have needed to create custom gesture recognizers for various reasons, just as I have and not all of those classes are exposed for us to use.
Check out http://oleb.net/blog/2013/02/new-undocumented-apis-ios-6-1/
BJ Homer believes UIGobblerGestureRecognizer is used to avoid
recognition while animations are in progress. Otherwise, it’s
inactive. In an interesting Twitter conversation, Filippo Bigarella
and Conrad Kramer discovered that UIGobblerGestureRecognizer can
“gobble” touches in order to prevent other gesture recognizers from
receiving them in certain situations. What situations those are, I
don’t know.
I'm very sure it is used to prevent normal interaction while a particular cell is showing a delete confirmation button, and recognise any touch down as triggering that cell to return to a non-editing state.
It has this method and I'm assuming that excludedView is the cell that is showing a delete confirmation button, since you can normally still interact with cells in this state.
- (id)initWithTarget:(id)arg1 action:(SEL)arg2 excludedView:(id)arg3;
https://github.com/nst/iOS-Runtime-Headers/blob/master/Frameworks/UIKit.framework/UIGobblerGestureRecognizer.h
In short, from what I've read and what my experiments have shown, the "gobbler" seems to gobble up the swipes and touches on a table view (actually table cells) when a state transition (initiated by the user's touch or swipe) is in progress, so that the state transition can be completed before the user can touch the table again. Apple may use it in other cases but it is on the table view that I have observed the gobblers.
Now the long story: Suppose your table view implements a "drawer" on the table cell, like Apple's mail app or message app. When you open the drawer with a back swipe and take an action on any of the buttons in the drawer, all is well. But if you just close the draw with a forth swipe, you'll likely find that your next back swipe on a random cell doesn't work. But if you keep doing the back swipes, the next swipe usually will work again to show the drawer. Simply put, if you just open and close the drawer on random cells by using swipes, you'll find sometimes the drawer doesn't open.
I see this behavior on my table and thought I did something wrong. I tried many things and eventually implemented my own subclass of UITableView which also supports UIGestureRecognizerDelegate. In my subclass I implemented the delegate's shouldBeRequiredToFailByGestureRecognizer function, just to print out the gestureRecognizer and otherGestureRecognizer pairs. Then I found that when the back swipe is recognized, the gobbler is NOT present in the pairs. But when the back swipe is not working, the gobbler definitely IS present.
The general opinion on the web is that the gobbler is used to prevent the user from causing another state transition on the table while one transition is already in progress. That is fine if the user indeed takes some action (by touching a button in the drawer). But when the user just closes the drawer, the gobbler should be cancelled. Or the gobbler should be added ONLY when the user takes an action. After my realization, I went on to try my theory on Apple's apps. I already knew the Mail app behaves perfectly responding to every swipe. But the Message app behaves intermittently to repeated drawer opening swipes, much like my app. So I guess the developers of Mail are more careful and used internal knowledge to get it right. My observation is done on iOS 8.4 on iPhone 6 and iPad 2. And I believe the same gobbler issue dates back at least from the first iOS 8 release because I know my app had the issue from day 1 (months ago) but I just got around to look into the problem.
it should definitely be part of private API ..
i will suggest to stay out of it

Multiple AVPlayers with AVPlayerLayers disappears second time push viewcontroller

I have a viewcontroller with four (4) AVPlayers (with AVPlayerLayers like APPLE example).
If I pop this viewcontroller and the push a new instance of the same type. I'm not able to play video in one or two AVPlayers. No errors and code runs fine, AVPlayerLayers also says it has a superLayer.
And to the most strange thing if I push home button, coming back to springboard and the enter the app all video players like magic start playing. It's like it rerender the view tree or something.
Any hints or clues?
PS. I wait for assets to be ready using loadValuesAsynchronouslyForKeys.
We had a similar problem. Following answer lead to the solution:
AVplayer not showing in ScrollView after 2-3 times
You have to call: [AVPlayer replaceCurrentItemWithPlayerItem:nil]; when your viewcontroller gets unloaded. This might be tricky as you might have added an observer or used addBoundaryTimeObserverForTimes:queue:usingBlock:
Also you have to be careful when checking agaings superlayer: Better check against uiview.window when determing whether your view is still attached to the view hierarchy.
yours
phil

Really strange behavior when trying to implement touch events

I'm working on my first iPhone application, and I'm getting some very strange behavior when I try to implement touch events.
I set up touchesBegan:withEvent: and its sister methods under a subclass of UIViewController, but they aren't registering. What's even weirder is that when I try using touches on the simulator while running the console, the console logs my touches, even though I have no NSLog statements in my program at all! At one point, I set up NSLog statements under touchesBegan:withEvent: etc., but I deleted them soon after. I have no idea where these logs are coming from.
Is this some issue with the responder chain? Why is the console behaving so weirdly? Any ideas?
Not weird at all. View controllers are just controllers - not views. You need to implement them in your UIView subclasses.
As for the strange console output - maybe a clean rebuilt will help, or we need some code to look at.