iOS NSNotification - Send notification to disabled View - ios

I have 2 UI views both with controllers attached to a tab controller.
ViewA - Used for authentication (contains login textfields and submit button)
ViewB - Used to display profile.
I have set ViewB to be disabled using the utility manager in storyboard, this is to prevent users clicking on the tab before logging in. Once authenticated in ViewA i want to notify ViewB to enable itself and display the profile.
From googling it appears that using NSNotificationcenter is the best way to do this, I have created a simple postNotifiaction that works fine - but I am unsure where to add the receiver in ViewB, I can not add it in ViewDidLoad because it does not load, and is disabled to start with?
Is notification center the best way to do this?
Also, how do i sent a notification to a view that is disabled?
Thanks

http://developer.apple.com/library/ios/#documentation/Cocoa/Reference/Foundation/Classes/NSNotificationCenter_Class/Reference/Reference.html
Apple documentation link above pretty clearly states that NSNotificationCenter does not retain it's observers, thats why you can't release the dataAnalyzer there - it would be dealloc'd and the notification would attempt to post to a nil reference.
Subscribe to the notification(s) in the -init method of each view controller. That ensures the controller has been created and initialized, and makes each controller responsible for it's own actions.
I'm not entirely sure what your question is, could you rephrase it if the above didn't resolve your problem.
Also, be aware NSNotificationCenter will post to all observers, but it is not async - it waits for each one to finish processing the notification before sending to the next object.

Surely, you have a controller (AppDelegate if anything) that controls the disabled state of ViewB? You could listen for the notification from this controller instance and enable ViewB from it once it receives the notification.
If you must subscribe to the notification from ViewB, then register for it in its (ViewB's) init method (don't forget to unsubscribe from the notification in the dealloc method). This should work because even though the button used to get to ViewB is disabled, the ViewB instance would be instantiated with the launch of your app (or so I assume...).
If you don't instantiate ViewB until the button is tapped, then you must have the controller that enables/disables the ViewB button be in charge of listening for the notification and enabling the button to access ViewB.

I think this logic is a little ambiguous. This is what I've understood about your application:
-> Tab Bar Controller
---> Controller 1 - Login
---> Controller 2 - Profile (disable as default)
You have not to insert you notify into Controller 2 but in TabBar because it "controls" the other controllers (sorry for the word joke). I think the best solution can bes this:
TabBar
Observer of a notification about "user changed" and check it: if user is logged then enable profile controller, if user is anonymous then disable it.
Controller 1 - Login
When the user is logged in / logged out fire a notification of "user changed".
That's all, your controller 2 can live without know user state. Let me know if you have problem coding this logic.

Why you not just call [viewB enableItselfSomehow]; in -someAuthenticationSucceedFeedback method?
Registering notifications for just enabling/disabling view is a bad tone as for me

Did you disable the view or the tab button?
If you disable the tab button, you could enable it and switch to the profile tab by doing
self.tabBarController.selectedViewController = profileViewController;
You can place this code in ViewA's view controller. To get the profileViewController, you can use this code instead
self.tabBarController.selectedViewController = [self.tabBarController.viewControllers objectAtIndex:1]
Assuming that your profile is at index 1

Related

Prevent dismissing modal WKInterfaceController

Is there a way to prevent the user from dismissing a modal controller?
I think it is pretty common to want to "block" the main Watch App interface while asking the user to open the iPhone counterpart or to perform some action there.
My current solution is to present again the controller when it gets dismissed but its clunky.
There's a somewhat kludgy way to get around this issue using reloadRootControllers. When you call reloadRootControllers(withNamesAndContexts:) with the name of a WKInterfaceController that you've named in your storyboard, it has a similar effect to presenting that controller modally. However, since it's now the root controller, it doesn't have a cancel button. I don't really like this, but it does get the job done.
Note this method is deprecated since watchOS 4.
Apple Documentation on reloadRootControllers(withNamesAndContexts:)
The trick is to make the modal screen fullscreen and change the inset top value for your main group.
You can't prevent a modal interface controller from being dismissed, as the system automatically dismisses it when the title is tapped.
Since your code isn't asked if it should happen, but only knows that it is happening, there's no way to intercept or cancel that action. The WKInterfaceController documentation briefly touches on this.
When the user taps the title string, WatchKit automatically dismisses the modal interface without taking any further actions.
What can you do?
While you don't know when the Cancel title is tapped, there is a hack which "hides" the Cancel title.
This may confuse users who might wonder how to dismiss the modal, or mislead others into thinking the modal couldn't be dismissed.
What does the HIG recommend?
Circumventing a Human Interface Guideline would likely degrade the entire user experience.
The top-left corner of the modal sheet is reserved for the Close button, which dismisses the interface.
Some users might be frustrated or annoyed if
there is no apparent way to cancel, or
the modal presents itself again after repeatedly being cancelled.
Since the user expects to be able to dismiss the modal, perhaps you could allow them to do just that, then simply display some form of reminder in the presenting interface controller (to log in, or enable permissions).

WKInterfaceController cancel button

Is there any way to know when the cancel/dismiss button is tapped on the Apple Watch?
- (void)didDeactivate
Is not an option because that is called whenever the watch goes dark. I'm trying to sync data with the parent iPhone app and this makes it tough to cancel an operation on the parent app.
While you can't get the cancel directly, you can tell which view controller is active (because your code displayed it) and then tell when they switch. So you can set some flags on display and on de-activate, to tell when the view controller with the cancel button goes away.
Think of it another way, if your view controller disappears and another one displays, the activate of the other controller tells you the watch did not sleep.
Unfortunately, the current version of WatchKit has no method to determine if the Cancel button is tapped. The closest you'll get is the didDeactivate event that you've already mentioned.

viewDidGetCoveredUpByModalPresentationFormSheet?

I have an app that has different integrations such as Evernote and Dropbox. When the user authenticates them, a UIViewController presents the authentication view as a UIModalPresentationFormSheet. This doesn't trigger viewDidDisappear for my view which makes sense since it doesn't disappear.
Is there another method I can implement that will be notified?
I assume you want to know when the modal view as been presented? Assuming you are using presentViewController:animated:completion , you can use the completion handler to know when the viewcontrollers view has been presented Here is a ref

How to present view controller properly?

I have a pretty simple application with a couple of UIViewControllers (say VC_A and VC_B). Every screen has a button that allows to switch to another screen (no UINavigation is used).
App schedules a local notification, which, when expired, should present another view controller (VC_N - no matter what screen is active at the moment).
The problem is that sometimes application throws:
'NSInternalInconsistencyException', reason: 'Attempting to begin a modal transition from
<VC_A: 0x2021e0> to <VC_N: 0xf84b970> while a transition is already in progress.
Wait for viewDidAppear/viewDidDisappear to know the current transition has completed'
What is the proper way to implement such behaviour?
A. Use UIViewController's new presentViewController:animated:completion to present all three controllers instead of the old modal method.
B. Create a Boolean flag and initialize it to NO.
C. Before any view controller presentation, check for this flag. If YES, set to NO. And then present the VC. In the completion block, set the flag to YES again.
D. The app should ignore this flag when present the initial view controller whether VC_A or VC_B.
One pitfall to this is that if a button got pressed or the local notification expired while already a view controller was in a transition state, then the new VC won't get presented. One can improve upon this logic to present it after if needed.
When the timer expires don't call the view presentation in that timer handler method. Instead try putting the view presentation call in a separate method and use [self performSelector: withObject: afterDelay:] to call that method (delay could be 0.1]. This should get the view presentation done when current transitions complete.

Adding control method(s) to button created in storyboard ?

I'm trying to add some finer control to the Storyboard controller and I hit a blockage with the back button.
I have a basic Storyboard with push transition. I want to be able to catch when the user presses on the back button (the one generated automatically) and decid if I want the view to go back or not.
The scenario is to show a message to the user asking if he wants to go back warning him that he is going to lose his work if he does,
Sounds simple, yet I can't find how to do it.
Any ideas
You don't get any sort of message by default when the back button is pressed. If you want to provide this sort of functionality, you have two options:
1) Provide a custom back button and set it as the leftNavigationItem of your UIViewController's navigation bar
2) Subclass UINavigationController and override a method such as popToRootViewController:animated:
Try using UIAlertView Delegate.
In your buttonPressed Action, provide an alert view with message with two buttons YES and NO.
define button at index action for YES and NO -ie- YES: dismiss current view and NO: remain on current view.
Search Apple Docs on alert view delegate

Resources