I have implemented Force Touch in my app in the chat view. When a user force-touches the chat message bubble of the other user, his/her profile is presented. For some strange reason, when the message bubble is gently pressed, the interactive transition gets stuck and all that is visible is a screenshot of the view that is supposed to be phased out.
I've debugged this issue as well using the View Hierarchy Debugger and the UITransitionView is definitely the top-most view. The app does not crash - it is still running and the user can still receive messages but not view them, exit out of the screen, etc. because of the screenshot stuck on top.
Has anyone ever had any issues like this? Sounds like an Apple bug.
I found a reason for this bug.
If your view controller need to support preview for force touch, you need register this view controller with delegate by calling
- (id <UIViewControllerPreviewing>)registerForPreviewingWithDelegate:(id<UIViewControllerPreviewingDelegate>)delegate
sourceView:(UIView *)sourceView NS_AVAILABLE_IOS(9_0);
method to do this.
I just suddenly call this function twice (once in super class' viewDidLoad(), once in subview controller's), and when I remove once in my subview controller, this bug is fixed! Amazing...
It's still an Apple bug since it makes no sence for that happens. However, wish this answer can help developers who has the same issue with me.
FYI. I just browse your Github code, found no double calls for register method. Maybe there's other reason for this bug. You could try to remove register method in your UITableViewController's subclass. By the way, I reproduce this issue when a view controller use ComponentKit.
Related
This question already has an answer here:
Swift 4 Odd unexpected jump back to earlier storyboard
(1 answer)
Closed 4 years ago.
Every time I tap somewhere along the top part of a view controller, it would return to the previous view. Root Controller is not affected as it doesn't have anything to return too. All of my View Controllers are affected though. (Please read update 3)
Things I've tried:
Looked for unnecessary gesture recognizer. (Result: I received nil when I check for the list gestures.)
I figured I might have accidentally added or left a IBOutlet to the view or something. (Result: There was no unnecessary IBOutlets.)
I disabled user interaction from a view to see if it would be affected. (Result: The bug seemed to go away until I enabled user interaction again.)
I've tried to do some research but I wasn't getting the results I wanted.
Tapping above the green line will make the View Controller return to the previous Controller.
I'm still relatively new to Objective-C and Xcode so I don't know if I'm making a rookie mistake or not.
UPDATE (Please read update 3)
Still nothing but here are a few more things i've tried:
Logging every user action.
Created a new project with new view controllers.
Opened a previous project to test it's view controllers.
Uninstalled and reinstalled Xcode.
All attempts still came with that weird bug.
UPDATE 2(Please read update 3)
I've decided to put a band-aid over the problem. Since the bug doesn't work when clicking over a button, I put constraints on a empty button, put it on top of the background image and removed the effect when button is tapped.
I thought this would work but there is a few spots on the screen that activates the bug. I experimented and figured that certain parts of ui elements activated the bug. (Example: Some labels in a Stackview, top part of a textfield, a switch, top part of a UICollectionView, etc.)
I've disabled user interaction for certain ui elements. Unfortunately not all ui elements could be disabled because some require user interaction.
Also I figure out that tapping with three fingers on the screen somehow activates the bug.
Here is an error code I received in the console when I was trying multiple taps on the screen:
<_UISystemGestureGateGestureRecognizer: 0x2822fc1e0>: Gesture: Failed to receive system gesture state notification before next touch
UPDATE 3
After playing around with the code again. I believe I've figured out what is causing the problem but not how to fix it.
I believe it has to do with the story board segue, or at least the transitions being used. If I set the kind to "Show(e.g. Push)" than it works fine, but if I set the kind to "Present Modally" and the transition to "Partial Curl", the bug does it's thing.
Sidenote: This is how I tested it. I created a new project (I don't think the language matters). The project has two view controllers; one button each with segue pointing at each view controllers. Segue 1 has it's kind as "Present Modally" and the transition as "Partial curl". Segue 2 is on the 2nd view controller and has it's kind as "Show(e.g. Push)". To test the bug, tap along the top part of the screen. If the bug worked, then it should show the partial curl transition but in reverse and send the user back to the 1st view controller.
maybe you are experiencing the standard swipe back gesture coming from the navigation controller. It thats the case try this code:
Objective-C:
if ([self.navigationController respondsToSelector:#selector(interactivePopGestureRecognizer)]) {
self.navigationController.interactivePopGestureRecognizer.enabled = NO;
}
Swift:
navigationController?.interactivePopGestureRecognizer?.isEnabled = false
I have a presentedViewController on top of the root view controller when the app gets dismissed. (e.g. User navigates to another app or goes back to the home screen.)
I would like to nil it out when the user reactivates the app without it being visible to them. Calling -dismissViewControllerAnimated: is not an option because it only works if the view controller is visible, and I'd like to do it sooner and specifically only in application:openURL:sourceApplication:annotation: and otherwise let the user continue their workflow in the modal view.
Are there any tricks I can use?
According to your comment, the only actual issue is what happens when the app receives application:openURL:sourceApplication:annotation: and is thus brought to the front.
In that case, simply adjust your interface in application:openURL:sourceApplication:annotation: - that is part of its purpose, to allow you to do that. You will be given some time before the "snapshot" is torn away, so if the adjustment involved is to dismiss an existing modal view, dismiss it without animation and there you are.
The user will still see the modal view for a moment, but not really - what the user is seeing is not your interface but the "snapshot" that was created by the system when the app when into the background. The "snapshot" is removed to reveal the actual interface (with a nice crossfade effect in iOS 7).
If the "snapshot" itself is problematic there are ways of preventing it from being taken, but it doesn't sound to me like this is that kind of situation.
(By the way, this raises the question of how the presented view is to know that it must be dismissed. The initial main action is in your app delegate, which is probably some conceptual distance away from the presented view. This would be an appropriate situation in which to use an NSNotification to communicate across this distance.)
I've been dealing with this (somewhat) random bug for a while and can't figure out the problem. The context: I'm creating an UISplitView iPad app that have a UINavigationController inside the Master view:
Main menu in red, submenu in green and main content in purple.
This UINavigationController does not fill the entire Master view because I need some space to have a vertical menu. When a user select a button on the vertical side menu, it sets something new to the UINavigationController to show a UITableView with options. What I'm doing on every menu selection is:
[self.subMenu setViewControllers:#[subMenuViewController] animated:YES];
What happens is that I don't need to keep the menu history, so what I do is I set a new root view controller to the subMenu every time.
The issue is when I start messing with the device orientation. It doesn't have a clear pattern, but sometimes, when rotating, my app crashes. Now when I run it with Instruments, this is what I get:
167 Zombie -1 00:32.101.527 UIKit -[UITableView _spacingForExtraSeparators]
And the interesting thing is that the bad access happens on the previous root view controller of the subMenu. So if I tap "Events" and then after that I tap "Podcasts", the bad access happens on trying to access "EventsViewController".
So I'm guessing something is not right on my way of replacing the root view controller of the subMenu UINavigationController, but I'm not sure what it is. Maybe I need to make sure the current root view controller is released before setting a new one?
Any help is much appreciated. :)
It's not uncommon to crash in system library code due to something you didn't set up quite right. This might be that your UIWindow, UIApplicationMain or its content view or your view controller instance was not retained or got released somehow.
That shouldrotate method won't help if your controller isn't still around.
This is to identify which object got released.
For particularly thorny problems, you could add release, retain, and dealloc methods (that log and call super) to a suspect class of yours and see what's releasing it. Log the -retaincount to keep track (I only use this for diagnostic purposes,)
Or you can try this, set a breakpoint on -[UIDevice setOrientation:] and step through your code in the debugger.
To make debugging easier, you can type call (void)instrumentObjcMessageSends(YES) right in the debugger console to begin logging objc_msgSends to /tmp/, then continue execution and it will trace all the messages that are sent right up until the crash.
So first, you should implement the methods willRotateToInterfaceOrientation, willAnimateToInterfaceOrientation and didRotateToInterfaceOrientation (check the actual signature of these methods) in your view controllers that contain a UITableView.
In each of these methods check the your table view dataSource and delegate. I think this crash is caused by a release of the delegate or table view's datasource.
Also you should check what table view delgate/datasource methods are called during rotation.
And the last thing, make sure you discard the old instances of subMenuViewController and they are properly removed from the parent view controller.
I've got a view Controller which manages my TV Playout (HDMI Apple AV Adapter). Everything works fine. I call my view Controller using a popover on the iPad.
When I open the popover, the external screen is recognized and I can work with it. But when I close the popover View (which means I send my TV Playout View Controller to the background) the TV screen (logically) turns black.
Is there a possibility to tell my view Controller to hold the picture on the TV screen by quit?
Like "pseudocode"
[TVOutViewController stayActiveInBackground]; //pseudocode
Thanks in advance!
I suspect you've coded your view controller so it explicitly shuts down the external UIScreen/UIWindow pair when it becomes inactive. I suggest you move the external screen code out of your popup's view controller and into an object which has a lifetime independent of what's going on on the internal screen, e.g. your application delegate or an object referenced by it. Then just send that object messages from your popup view controller in response to user events.
There's nothing about the Apple APIs that causes this kind of behaviour - it's purely a consequence of how you've designed your app. As such I don't recommend trying to force the view controller to stick around. Instead, try to find a better structure for the app. A view controller should only be responsible for its view, not application state.
OK guys, By chance, I found a solution (or at least a workaround). Be sure to manage the problem using a UISplitViewController with your TVOutViewController as the masterViewController and the ContentViewController as the detailViewController. Apple already did the work. Thanks anyway! :)
How do I make a curled-up view update live as the user interacts with view being presented with presentModalViewController: under it?
The behaviour I want:
User taps a view settings button.
User taps controls in the view settings screen. Rather than dismissing view settings, the view automatically updates in the background.
User taps something to dismiss view settings.
Imagine if in Maps tapping Map, Satellite, Hybrid didn't uncurl automatically but just updated the display.
I'm able to get notification that something's changed from the settings controller back to the main view controller. The main view controller can update and signal that it should redraw parts of itself, but actually updating the screen is intermittent. It will work 5 times in a row, then not work a couple times, then work another 5 times in a row. Dismissing the modal view always catches up the view underneath, however, so I assume the rendered image of my view is sometimes being cached or not being redrawn despite my request. But I can't think of a way to verify this.
This happens on both the device and the simulator.
While there might be multiple root causes of this behavior, here's a common issue I've seen that causes 'delayed' or 'intermittent' updates to UIKit views.
If the statements that update your presenting view (or the presented view) are running in a dispatch queue other than the main queue, UIKit may produce inconsistent results and timing in the actual UI update. You can usually tell by putting a breakpoint on the statements that update the UI and examining the name of the 'queue' displayed in Xcode's left-side debugger view. It should be 'com.apple.main-thread'. If it's not, that could be your issue. This can happen in quite a few delegate methods such as the network APIs.
Try wrapping your UI updates in:
dispatch_async(dispatch_get_main_queue(), ^() { ... }); and see if that helps! You should only do this when needed and take care to use block-safe techniques as always.
I tested this in a brand new Universal app for iOS 7.0.3 using the iPad simulator with a view controller presented using the partial curl transition. I was able to replicate the original issue, including the intermittent update and the 'snap' update when dismissing the presented view by using a background queue in the code I provided above. Once I switched to the main queue, everything worked A-OK.
Let me know if this helps or if there was some other issue :)