What architecture can I use to change screens in Swift when there's an event outside of the current view? - ios

For example, I have a Notification that occurs when there is an "unauthorized" error returned from the api server that should bring the user back to the login screen. This event could appear anywhere in the program.
Do I create a new viewless controller to manage states and have it monitor for this notification and then present the login view controller?
I'm thinking about push notifications too, received by the app delegate. Some of these may cause the data model to get updated and then the screen to change. Who should make the screen change? In the past I put all this in the AppDelegate. But there must be a more elegant way!
I also found out about FlowControllers. But they don't play nicely with Interface Builder, at least according to this solution.
Please let me know if you need more specific information about my project.

Related

iOS Push Notification with Rich Content - Can I prevent a notification from being tappable?

I have a push notification with rich content.
Can I make it in such way that it is not tappable, i.e., a single tap will not open the application. It must be dragged down to rich content or 3D touched, or deleted from the notification center by swiping.
How should I indicate to the user to drag down (3D touch) in order to reveal rich content on notification?
No, a tap on a push notification will always open the notification in the app, and as far as I know there is no way in public API to override this behavior. It does appear there is a private API to get the behavior you’re looking for, as some iOS-generated (local, not push) notifications appear to do exactly what you’re asking. If you can manage to uncover that, use at your own risk should Apple find out.
Now, as for possible solutions: I would consider implementing code on your app’s delegate to respond appropriately when the notification is opened. For example, send the user to an appropriate location in the app when the app is launched from a notification…perhaps a view controller that shows the same content that would be shown as the rich notification content. I don’t know the exact use case, but the wording implies to me that if the app launches to its main interface, it could be confusing to a user.
It’s impossible for me to tell you how exactly you wish to respond to notifications, so for more on responding appropriately when the app was launched from a push notification, see the following documentation from Apple:
Determine Why Your App Was Launched
UIApplicationDelegate.application(_:willFinishLaunchingWithOptions:)
UIApplicationDelegate.application(_:didFinishLaunchingWithOptions:)
UIApplication.LaunchOptionsKey
UIApplication.LaunchOptionsKey.remoteNotification
Hopefully from that you can find a suitable solution. But if that isn’t an option, consider directly telling the user at some point to press firmly (or tap and hold, as many devices do not support 3D Touch) to view the content. You could do this during some onboarding process or, as an absolute last resort, in the notification itself.
Before proceeding down that route, though, understand that not all users know 3D Touch and/or this rich-content functionality even exists — even fewer use it regularly — and if they become confused, they may decide to clear the notification or outright disable your app’s notifications. In general, it’s also a bad idea to “teach” your user unfamiliar ways of using their device. If a user is used to tapping on notifications, as many are, they will most likely tap on your notifications. It can be tough to break that muscle memory.

Firebase Analytics Continuously Tracks UINavigationController

I'm transitioning from Google Analytics to Firebase Analytics. Unlike Google Analytics, Firebase automatically tracks screen views, which is great! But, instead of tracking the screen, it continuously attempts to track the UINavigationController. I get the following error log twice every time I navigate to a different view controller.
[Firebase/Analytics][I-ACS031006] View controller already
tracked. Class, ID: UINavigationController, -1770652405567491888
Is there some configuration required when you have a navigation controller? How do I get automatic screen tracking working in this scenario?
UPDATE: I haven't found a solution to this yet, but I at least found the cause of the problem. It looks like Firebase doesn't understand your view controller hierarchy if your initial view controller is a Tab Bar Controller. My initial view controller in my main story board is a Tab Bar Controller. If I take this out, I get good screen tracking reporting from my app.
UPDATE: It looks like I've found an OK solution to this, but I'm still wondering if someone has a better idea. Since Firebase sees all of the view controllers under my Tab Bar Controller as the same UINavigationController, I can call setScreenName manually in viewDidAppear for all of them.
Analytics.setScreenName(screenName, screenClass: screenClass)
This is OK because it's not any worse than Google Analyics, but it's not ideal because the system still tries to track the UINavigationController twice for every view controller and I'm also not getting the benefit of automatic screen tracking. I looked into trying to remove the Tab Bar Controller from Firebase as some folks seem to have done, but it looks like those methods have been removed from the current (v4.0.0) version of the Firebase SDK.
Screen is automatically tracked in Google Analytics for Firebase. You can see it in the user engagement card in the Main dashboard. This has been introduced in Firebase Version 3.8.0 for iOS. More in track screen doc. Quoting from the doc:
Events that occur on these screens are automatically tagged with the parameter firebase_screen_class (for example, menuViewController or MenuActivity) and a generated firebase_screen_id. If your app uses a distinct UIViewController or Activity for each screen, Analytics can automatically track every screen transition and generate a report of user engagement broken down by screen.
However, you can also track screens manually using the setCurrentScreen() method. The details on this screen should be available in the user engagement card when you select the ScreenName from the dropdown, all the screens manually tracked in the code should be displayed there with the breakdown of duration on average.
Please note that the setScreenName is not an event, it is rather an event parameter that goes with the event that is tracked in the logEvent() method call.

How does iMessage preserve viewController state after view disappears?

I observed that iMessage preserves last typed message in a chat even if I move to another chat and come back to it.
For eg. I am in Chat1 and typing. Then without sending the message I move to Chat2 and then come back to Chat1. Last typed message is still there.
If I understand correctly, when I press back button in Chat1, it should execute viewWillDisappear which should destroy all local elements.
Then how is last typed message still there?
iMessage is not the only app which does it. Whatsapp also does it. Even you open a chat in whatsapp scroll to older message->go back->and come again on the same chat. You will see the old state of chat.
The Recommended way to do it is App State Restoration if you want to store the whole state of your controller with more UI elements and values.
You can check following tutorial available for this..
https://www.raywenderlich.com/117471/state-restoration-tutorial
http://useyourloaf.com/blog/state-preservation-and-restoration/

IOS initial view controller based on condition retrieved from database

An iOS app I'm creating shows a setup screen upon first launch which requires data to be written to the database.
Upon launch, I need to access this value form the database.
If it is set, launch main view controller
Else show setup view controller.
As far as I'm aware theres two ways I can do this, programmatically setting it from the AppDelegate or using an initial View Controller as a splash screen and performing the look up and segue there.
What would be the best way to approach this? Is it wrong to do a database lookup in didFinishLaunchingWithOptions?
Using a splash screen is probably the better option as it provides better scope for modification in the future and allows you to update the user on progress. It is fine for the app delegate to run logic to determine how the app starts but you should endeavour to keep the app delegate minimal and focussed.
I very much doubt that you would get this approved (if your goal is the App Store). Your app delegate needs to create a window, and set a rootViewController to that window before it returns YES in appFinishLaunching:
You simply do not have enough time to check with a server before creating the first viewController and you'll be creating poor interface if you try. I suggest the first ViewController will need to be informing the user that it is checking with the server with an activityIndicator or something. The best :)

Global app remote notification response ios

I would like to implement a similar response system for push notifications throughout my app. When a remote notification appears and the application is in the active state I would like to place a button temporarily on the screen that performs the same action regardless of where it is in the app.
The only way I can think to do this is to create the same response to notification method in each of the app's many view controller.
Is there any way to do this in the app delegate, tab bar, or navigation bar so that the same response would apply to multiple views rather than placing the same function in each view controller separately?
Please advise and thanks
If I understood your question correctly: your problem is not related to notifications at all, but rather how to place a button on top of all views. A common way would be to add it as a subView to the window.
As a starting point: AwesomeMenu on GitHub

Resources