iPhone - App still running, receive push notification = change view - iphone

I'm trying to change view upon receive a push notification while the app is still running. I tried using this in the AppDelegate.m
-(void)application:(UIApplication *)application didRecieveNotification:(NSDictionary *)userInfo
{
TestClass *aTestClassViewController = [[TestClass alloc]initWithNibName:#"TestClass" bundle:nil];
[self presentModalViewController:aTestClassViewController animated:YES];
[aTestClassViewController release];
}
But it didn't work. I can't even start up the app again. so I'm guessing this is the wrong way to do it.
Any idea guys? I would appreciate it.

Solved***
I did it this way ->
I showed an alert view first (Which i needed anyways)
then used the method of
-(void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex{
TestClass *aSelectionScreenViewController = [[TestClass alloc] initWithNibName:#"TestClass" bundle:nil];
[viewController presentModalViewController:aSelectionScreenViewController animated: YES];
[aSelectionScreenViewController release]; }

We're missing some context about your application, but your basic problem is that it's the application delegate object which is receiving the notification, not a view controller. That's why you can't just do [self presentModalViewController:someViewController];
I think it's the snippet from your own answer that gives what you need: your app delegate (presumably) has a 'viewController' member, which is the root view controller for the application. It is that viewController object you need to prod into doing whatever it is you need. In the app I'm looking at right now, I have a tabBarController member in the app delegate, and I show an alert view and/or change the selected tab index when a notification comes in.
I would have your app delegate call a function on your main view controller when a message comes in, and have that function show the alert view, then do whatever state changes you need to do to make the main view controller reflect the received notification.

Related

Load view every time when app becomes active

I am making a some kind of password security in my app, so nobody except the iphone owner can open an app. And I'd like to load my password view which I created every time when user clicks on the app icon.
I know there is a nice method in AppDelegate called -(void)applicationWillResignActive:(UIApplication *)application. However, in AppDelegate you are not able to use presentModalViewController: animated: which I like so much.
How can I load a password view every time, when user opens the app ?
Thanks.
In the AppDelegate, you will certainly load a view controller somewhere. E.g. a navigationcontroller:
-(void)applicationWillResignActive:(UIApplication *)application {
// probably more code....
[window addSubview:navigationController.view];
[window makeKeyAndVisible];
return YES;
}
now, in this navigationController, you could write a method like
(void) lockScreen {
// code to for presentModalViewController: animated:
}
I'd use applicationDidEnterForeground
- (void)applicationDidEnterForeground:(UIApplication *)application {
[navigationController lockScreen];
}
use nsnotification to do that. add an observer with a method which perform presentation of model view and in didBecomeActive. post the notification.

iPhone App - dismissing modal view controller doesn't dealloc it

I have a UIViewController (call it NumberTwo) which I presented as a modal view controller from another UIViewController (call it NumberOne). NumberTwo contains a touchesBegan method which listens for touches, and it also has an accelerometer method which listens for device orientation changes in the x, y, or z direction. NumberTwo has a button called "Done" which, when tapped, dismisses itself as a modal view controller:
[self dismissModalViewControllerAnimated:NO];
But it seems as though it's still listening for touches, and it's still listening for accelerations. How can I completely free up NumberTwo when I dismiss it? I tried adding a release call as follows:
[self dismissModalViewControllerAnimated:NO];
[self release];
but that caused a EXEC_BAD_ACCESS.
Did you release the controller after you presented it? E.g. in your method in NumberOneController that presents it, do you have something like:
NumberTwoController * controller = [NumberTwoController alloc] init];
// do stuff to config controller
[self presentModalViewController: controller];
[controller release];
Unless you want to hang on to NumberTwoController for re-use, this would be the usual pattern. The presentModalViewController method ensures that the controller is retained while it's in use. It should then get tidied up when, within NumberTwoController, you call [self dismissModalViewControllerAnimated: NO].
I had a very similar issue that plagued me for days. It turned out that my view controller class wasn't being deallocated when I dismissed it because that view controller had an active NSTimer that wasn't being invalidated (stopped). I was able to kill the timer in viewDidDisappear.
Make sure you are releasing everything you use when you finish with it; The dealloc method is only called when the UIViewController and all of its properties/objects are no longer in use. Never use [self release]; you need to release it from the view controller that created it after you are finished with it.

iphone - Modal view controller disappears?

So let's say I have a viewController named homeViewController, and another view controller named listViewController
I display listViewController on top of homeViewController as a modal.
If the user clicks the off button, and then comes back to the app the modalViewController is gone.
ListViewController *listViewController = [[ListViewController alloc] init];
[self presentModalViewController:listViewController animated:NO];
[listViewController release];
Note: Application doesn't startup from scratch when this occures and the previous state is still visible
I'm assuming that by "off button" you mean the user locks the iDevice.
I just tried this in one of my apps and the modal view controller is still there after unlocking. My guess would be that it's something unrelated to the code you have posted. I would check your - (void)applicationWillResignActive:(UIApplication *)application method in your app delegate class and see if there's anything there that would dismiss the modal view controller.
Here is what the problem was.
When the user locks the screen I remove homeViewController from window
[homeViewController removeFromSuperview];
When user starts the app again I do
[windows addSubview:homeViewController];
that brings homeViewController on top of its modeal

Message sent to deallocated instance

I have an app that navigates thru different views using the navigation controller. This is what I’m doing:
MapViewController *aMap = [[MapViewController alloc] initWithNibName:#"MapView"
bundle:nil ];
[self.navigationController pushViewController:aMap
animated:YES];
[aMap release];
At an user action, I want to go back to the first view. This is what I did:
-(void)alertView:(UIAlertView *)alertView
didDismissWithButtonIndex:(NSInteger)buttonIndex
{
[self.navigationController popToRootViewControllerAnimated:NO];
}
When I press a button that call the bellow method, my app goes as expected to the first view. But the problem arises when I press the “Home button” and try to reopen the app. Then, the app crash giving the following error:
2010-12-23 14:33:18.504 test[4549:307] *** -[MapViewController respondsToSelector:]: message sent to deallocated instance 0x5c26320
I understand that I sending a message to an instance of the object that does not exist, but I don’t find where is this happening
Do you have any recommendation?
Something is trying to send messages to the MapViewController after it's been deallocated.
Are they any objects that reference it - is it the delegate for any of its subviews, or does it receive any notifications, or anything like that?
If so, you need to make sure you unsubscribe from any notifications in the controller's dealloc method, and set any delegate parameters (on other objects) that reference the controller to nil.

presentModalViewController crashes my app

It's one of the simplest things to do, I know. But I've been banging my head against this for days. I've done it plenty of times in the past, but for some reason trying to present a modal view controller just crashes the app to a black screen. Nothing reported in the console or anything. I'm hoping someone might have had this problem and has some advice.
This code is called from a UIViewController class:
MFMailComposeViewController *controller = [[MFMailComposeViewController alloc] init];
controller.mailComposeDelegate = self;
[controller setSubject:#"test subject"];
[controller setMessageBody:#"this is the message body" isHTML:NO];
[self presentModalViewController:controller animated:YES];
As Andrew has pointed out in his comment, do you check
+[MFMailComposeViewController canSendMail]
before trying to push the view controller? The behavior of the MFMailComposeViewController is not well defined if this method returns NO (which may also well be the case when running on the simulator, though I'm not sure). From the documentation:
Before using this class, you must
always check to see if the current
device is configured to send email at
all using the canSendMail method. If
the user’s device is not set up for
the delivery of email, you can notify
the user or simply disable the email
dispatch features in your application.
You should not attempt to use this
interface if the canSendMail method
returns NO.
Have you tried to push another view controller instead? Does this crash your app, too?
Are you showing another modal view controller before trying to show MFMailComposeViewController? I had the same problem and found a workaround:
- (void)peopleMultiPickerNavigationController:(PeopleMultiPickerNavigationController *)peoplePicker
didSelectContacts:(NSArray *)contacts {
[self dismissModalViewControllerAnimated:YES];
// some more code here
[self performSelector:#selector(sendEmail) withObject:nil afterDelay:0.45]; // this works only if delay > ~0.4!
// [self sendEmail]; // this won't work
// some more code here
}
- (void) sendEmail {
Class mailClass = (NSClassFromString(#"MFMailComposeViewController"));
if (mailClass != nil) {
// We must always check whether the current device is configured for sending emails
if ([mailClass canSendMail]) {
[self displayComposerSheet:emails];
} else {
[self launchMailAppOnDevice:emails];
}
} else {
[self launchMailAppOnDevice:emails];
}
}
I know it's an ugly workaround, but I didn't found anything better :(
I don't know how relevant this is, but I have been having horrible problems trying to present the MFMailComposeViewController after returning to my main view controller from ANOTHER modal view controller. It just would not work. I was trying to dismiss this other modal view controller before launching the mail controller, and found my solution to be to not call:
[self dismissModalViewControllerAnimated:YES];
But to instead call:
[self dismissModalViewControllerAnimated:NO];
Then go ahead and present the mail view controller.
That one change made all the difference in my case. I suspect this is connected to the problem sgosha was having. Just switch off the animation, rather than putting a delay in (which is probably just waiting until the animation has completed). Looks like a bug in the framework to me.
I should probably explain further. I have a share button on my main view controller, which modally pops up a table view to allow to user to choose what they want to share. From here, if they tap on Email, they get a UIActionSheet letting them further decide which files they wish to attach to their email.
It is possible the UIActionSheet in the mix is contributing to the problem. The actual dismissal of the modal view controllers is taking place in the delegate methods back in my main view controller, and it is this main view controller which tries to launch the mail view controller after dismissing the modal table view controller.
Yes! I did it! I can not believe, but I solved the problem! That's related to:
Opening an MFMailComposeViewController as modal from (and over) some other opened modal controller
Unfortunately, I have to admit that, again, in times of expensive-like-a-Devil-iPhones5, Apple still forses developers to use old, buggy and not convenient code and components! The great example of that is MFMailComposeViewController.
But now let's follow to more pleasant things.
What do we have:
This problem appeared as on iPhone with iOS 5.1 as on Simulator with iOS 6.
The core problem was when you are trying to open the email controller as a modal one from another modal controller.
[MFMailComposeViewController canSendMail] had absolutely no effect for me - it did not work in both ways (it was crashing with or without email functionality available).
[self dismissModalViewControllerAnimated:NO/YES] did not change general sense - it was crashing in both ways, but with a little different behavior.
I was trying to use a standard approach with mailComposeDelegate (like '.mailComposeDelegate = self').
I was calling the email sending controller from both: common (first-level) controller as well as from modal (second-level) one at the same app.
App was not always crashing - sometimes the controller just could not dismiss itself (buttons 'cancel' and 'send' were active, but no actions processed). Dependenly on conditions (who is parent opened the controller, was animation or not on appearing etc).
There were also no difference if any email recepients were added or not.
So, what my killed 5 working hours discovered is that seems the delegate is "releases" somehow somewhen. I can suppose that if you are opening the email controller as modal over some other modal controller, that (previously modal) controller is being cleaned by garbage collector or some other way and that way the delegate is being cleaned as well (I have no wish to kill several more hours for detailed digging, so I'd leave that to Apple's conscience).
Anyway, in two words, my solution was
to hold the delegate object somewhere with "strong" reference.
in my case, the owner of that delegate was main view controller class (which is always available in my case, as most of the app logic is working with it). That can be AppDelegate instance also.
It would look like:
#interface SharingTools : NSObject <MFMailComposeViewControllerDelegate>
#property UIViewController* currentParentController;
...
-(void)mailComposeController:(MFMailComposeViewController *)controller didFinishWithResult:(MFMailComposeResult)result error:(NSError *)error
{
if (error)
{
...
}
else
{
// I pass it somewhere before calling the email controller dialog opener method,
// because it's different in case we open the email sender
// from first-level controller or second- (the modal one)
[currentParentController dismissViewControllerAnimated:YES completion:^{
if (_onResult) {
((void(^)(bool))_onResult)(result == MFMailComposeResultSent);
}
}];
}
// and of course clearing all the references etc here
currentParentController.mailComposeDelegate = nil;
currentParentController = nil;
}
-(void)sendEmail //... params here
// (possibly, including to store also currentParentController)
{
currentParentController = ... ;
[currentParentController presentViewController:
newlyCreatedEmailController animated:YES completion:nil];
}
#end
#interface MyMainViewController : UIViewController
#property SharingTools* sharing; // initialize somewhere (on viewDidLoad, for instance)
...
-(void)showSettings
{
...
[self presentModalViewController:settingsController animated:YES];
}
#end
#interface SettingsViewController : UIViewController
...
-(void)sendEmailSupport
{
// again, this is up to you where and how to have either reference
// to main controller (or any other owner of the delegate object)
// or sharing directly
[myMainViewControllerInstance.sharing sendEmail: ... parentController:self];
}
#end
Frankly saying, the code is kind of messy, but this is just general thoughts.
I hope, you'll manage your own much nicer.
Good luck and God bless Microsoft! ^^