Displaying a subView in didReceiveRemoteNotification? - objective-c

What Im trying to do is displaying my subView in didReceiveRemoteNotification when the app receives a notification and is running. How can I do this?
My code right now in didReceiveRemoteNotification:
UIApplicationState state = [application applicationState];
if (state == UIApplicationStateActive)
{
AcceptAlertViewCreator *acceptAlertViewCreator = [[AcceptAlertViewCreator alloc] init];
//Here I try to get the current viewController running...
UIViewController *viewController = [[[[UIApplication sharedApplication] keyWindow] subviews] lastObject];
//This line gives me the "Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[UIView view]: unrecognized selector sent to instance 0x17816b7c0" error
[viewController.view addSubview:[acceptAlertViewCreator createAlertViewWithViewController:viewController andText:[[userInfo objectForKey:#"aps"] objectForKey:#"message"]]];
}
else
{
//other things
}
My AcceptAlertViewCreator returns a UIView and gets a viewController for the viewController to be displayed in and NSString for message. My AcceptAlertViewCreator also has a UIViewAnimation when it is played.
My AcceptAlertViewCreator works great when added to a normal ViewController subView.
Anyone knows how I can accomplish this? Id doesn't have to be adding a subView. It could be a workaround in some ways, or please give me some pointers. Thanks

Instead of getting the viewController from sharedApplication just get the rootViewController of you window
You didReceiveRemoteNotification method should look like this:
UIApplicationState state = [application applicationState];
if (state == UIApplicationStateActive)
{
AcceptAlertViewCreator *acceptAlertViewCreator = [[AcceptAlertViewCreator alloc] init];
[self.window.rootViewController.view addSubview:[acceptAlertViewCreator createAlertViewWithViewController:self.window.rootViewController andText:[NSString stringWithFormat:#"%#", [[userInfo objectForKey:#"aps"] objectForKey:#"message"]]]];
}
else
{
//other things
}

So you are having your AppDelegate display a window when an alert comes in.
I would not add it as a subview, I would just present the view controller instead. I assume you want some action to be taken when this notice comes in.
You could also use NSNotificationCenter to send a notification to your app when the push notification comes in. You trigger the NSNotification from didReceiveRemoteNotification and your app views would need to listen for this notifications. The downside is each view would need to listen for this notification.

Related

how to pass information from Objective-c's viewcontroller to a Swift storyboard

I started to work in a project which was already started in ObjectiveC and without Storyboard. I'm making the new sections in Swift and with Storyboard, but now I'm having a problem when I try to pass information (an UIImage) to my storyboard's controllers.
This is how I go to the ViewControllers:
-(void)expenseCamera:(VOCCustomCameraVC *)camera didFinishPickImage:(UIImage *)
image imageCreated:(NSString *)imageCreated
fileName:(NSString *)fileName {
[camera dismissViewControllerAnimated: YES completion: nil];
UIStoryboard *addExpenseStoryboard = [UIStoryboard
storyboardWithName:#"addExpense" bundle:nil];
CreateExpenseVC *createExpenseVC = [addExpenseStoryboard
instantiateViewControllerWithIdentifier:#"expenseNavController"];
UIImage *compressedImage = [UIImage compressImage: image];
createExpenseVC.expenseImage = compressedImage; // It crashes here
//createExpenseVC.delegate = self;
[self presentViewController: createExpenseVC animated: YES completion: nil];
CFRunLoopWakeUp(CFRunLoopGetCurrent());
}
If I take out the createExpenseVC.expenseImage = compressedImage everything goes well, but when I try to pass the image I get this error:
SIGABRT *** Terminating app due to uncaught exception 'NSInvalidArgumentException',
reason: '-[YourApp.CustomNavController setExpenseImage:]: unrecognized selector
sent to instance 0x12e09b200'
The destination viewController starts this way
#objcMembers class CreateExpenseVC: UIViewController {
/* ---- IBOutlets ---- */
#IBOutlet weak var containerView: UIView!
#IBOutlet weak var backButton: UIBarButtonItem!
#objc var expenseImage: UIImage?
And in the containerView I show another viewController where I pretend to show the image.
I tried to change the code I use to navigate to this
CreateExpenseVC * createExpenseVC = [[CreateExpenseVC alloc] init];
But it also crashes because (I think) it's not instantiating the Storyboard and therefore not recognizing all the IBOutlets and so on...
So how can I pass information like this?
Many thanks in advance
I tried to replicate your problem with the way you have implemented and it worked fine for me.
But your error said, that [YourApp.CustomNavController setExpenseImage:] is not implemented. That means your view controller is embedded inside a navigation controller.
And you are trying to get navigation controller by this code
[addExpenseStoryboard
instantiateViewControllerWithIdentifier:#"expenseNavController"]
so your createExpenseVC is actually of type Navigation controller and not CreateExpenseViewController.
And that is why it doesn't get the expenseImage.
That is where your problem lies
Here is what you can do..
UIStoryboard *addExpenseStoryboard = [UIStoryboard storyboardWithName:#"CreateExpense" bundle:nil];
UINavigationController *navController = [addExpenseStoryboard instantiateViewControllerWithIdentifier:#"ExpenseNavC"];
CreateExpenseViewController *createExpenseVC = navController.viewControllers[0];
UIImage *image = [UIImage imageNamed:#"383975"];
createExpenseVC.expenseImage = image;
[self presentViewController: navController animated: YES completion: nil];
When dealing with this issue, I would check multiple things.
Is storyboard ID assigned?
Is the correct UIViewController class assigned?
Is the UIViewController has view outlet?
Check these screenshot for a visual guide:
View controller identify inspector screenshot
View controller view outlet screenshot

How to not push a segue into the Nav Controller Stack?

I would like to know what kind of trick to use for "not pushing" a view controller into the navigation controller stack (iOS)
I have this :
If user is not logged, show view A then show B
If user is logged, show B
As I am using the storyboard, I used a performSegue if the user is logged so he goes directly to B. But with this method, the Navigation Controller gets a push of view A in the stack.
I was thinking of poping out a level of the stack in some void (but I don't know how to do this).
I was also thinking of not pushing the view into the nav controller stack (but I don't know how to do this).
Thanks
Update :
I tried this :
//The view B
TabBarMain* mainViewController = [[TabBarMain alloc] init];
//If already logged in
if([username length] == 0)
{
NSArray *viewControllers = [NSArray arrayWithObject:mainViewController];
[self.navigationController setViewControllers:viewControllers animated:NO];
}
The problem of this code is that it shows me a black screen (doesn't crash). It seems that I need to init something and I have nothing in my TabBarMain.m, I don't know what to write in there. This TabBarMain is linked to the Tab Bar Controller of the Storyboard.
Is there no other way ?
Try this on for size in your rootViewController's viewDidLoad.
- (void)viewDidLoad
{
NSArray *viewControllers
if (logged) {
NSArray *viewControllers = [NSArray arrayWithObject:viewControllerB];
} else {
NSArray *viewControllers = [NSArray arrayWithObject:viewControllerA];
}
[self.navigationController setViewControllers:viewControllers animated:NO];
}
Since your viewController is linked in Storyboard and not instantiated in code you need to instantiate it from the storyboard not your empty code. Make sure the identifier matches the identifier for your ViewController in your storyboard.
TabBarMain *mainViewController = [[UIStoryboard storyboardWithName:#"MainStoryboard" bundle:NULL] instantiateViewControllerWithIdentifier:#"tabBarMain"];

Game Center Calling Leaderboard function not responding?

I am calling the leader board like this:
-(void)viewscores:(SPEvent*)event
{
GKLeaderboardViewController *leaderboardController = [[GKLeaderboardViewController alloc] init];
if (leaderboardController != nil) {
leaderboardController.leaderboardDelegate = self;
UIWindow* window = [UIApplication sharedApplication].keyWindow;
[window addSubview: self.rootViewController];
[self presentModalViewController: leaderboardController animated: YES];
}
}
When I Click the leader board button, I receive an error:
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '+[UIViewController presentModalViewController:animated:]: unrecognized selector sent to class 0x3e2fc7f8'
Is this normal?
You should probably call the function in a viewController. In one of my app's the code looks like this:
-(IBAction)showLeaderBoard {
GKLeaderboardViewController *leaderBoardCont = [[GKLeaderboardViewController alloc] init];
if (leaderBoardCont) {
leaderBoardCont.category=#"1S";
leaderBoardCont.timeScope=GKLeaderboardTimeScopeWeek;
leaderBoardCont.leaderboardDelegate=self;
[self presentModalViewController:leaderBoardCont animated:YES];
}
}
and then you should also implement the delegate method:
-(void) leaderboardViewControllerDidFinish:(GKLeaderboardViewController *)viewController {
[self dismissModalViewControllerAnimated:YES];
viewController = nil;
}
Here 1S is the identifier for the leader board you created in iTunes Connect. Hope this helps.
Edit: since you are still having problems, check these tutorials out. They cover everything about leader boards and achievements.
1st part
2nd part
You're sending the presentModalViewController message to an object that doesn't recognize it. So the class you wrote in your "Game.m" file doesn't inherit from UIViewController. Dunno what framework you're using, but you'll have to init a UIViewController instance to show the GameCenter view.

Remove all settings from viewcontroller when dismissed

I got multiple viewcontrollers in my project. The first viewcontroller is called when the application starts and it presents a login screen. When the credentials are correct and the user logs in, the modalview is dismissed. and another viewcontroller is instantiated like this:
[self dismissModalViewControllerAnimated:NO];
Form *formcontroller = [[Form alloc] init];
[self presentModalViewController:formcontroller animated:YES];
When my other viewcontroller is presented the old one disappears. On the top of my secondviewcontroller i got an logout button, wich does exactly the same, so it dismisses the current viewcontroller and calls another like this:
-(IBAction)logOut:(id)sender{
[self dissmissModalViewControllerAnimated:NO];
}
And in my viewdiddisappear:
-(void)viewDidDisappear:(BOOL)animated{
Postform3ViewController *logincontroller = [[Postform3ViewController alloc] init];
[self presentModalViewController:logincontroller animated:YES];
}
The problem is:
When i push the logout button, and i return back to the logincontroller. The Credentials are still filled in. So my conclusion is that the first viewcontroller stays in memory. What am i doing wrong?
Edit:
I did find my own solution. I was profiling my application, and couldn't find any memory leaks. So i decided everything is released. Then i thought that i was able to set everything to empty myself. I did that in the viewDidAppear method like this:
-(void)viewDidAppear:(BOOL)animated {
gebruikersnaam.text = #"";
wachtwoord.text = #"";
[self.activeTextField resignFirstResponder];
[super viewDidAppear:animated];
}
Well first of all when you are using presentModalViewController and pushViewController the VC is retained so you should always release it after you have presented or pushed it.
Secondly in the third block of code it looks like you are creating a logincontroller but presenting a formcontroller. Perhaps you want to be presenting the VC you had just created:
[self presentModalViewController:logincontroller animated:animated];
Edit 0: For your code, in the first block, release like this:
Form *formcontroller = [[Form alloc] init];
[self presentModalViewController:formcontroller animated:YES];
...
[self dismissModalViewController:formcontroller animated:YES];
[formcontroller release];

App crash when view controller with content is pushed

UITabBarViewController & UINavigationController & UITableView
My app crashes when I try to push a detail view controller when selecting a cell.
If I empty the detail view controller I am trying to push, it works, but when I add UITextFields and action buttons to the view, the app crashes.
Here is my code:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
NSUInteger row = [indexPath row];
if(self.addSimpleTrainingVC == nil)
{
AddDetailVC *tempVC = [[AddDetailVC alloc] initWithNibName:#"addDetailVC" bundle:nil];
self.addDetailVC = tempVC;
[tempVC release];
}
addDetailVC.title = [NSString stringWithFormat:#"%#",[myArray objectAtIndex:row]];
[self.navigationController pushViewController:self.addDetailVC animated:YES];
addDetailVC.title = [NSString stringWithFormat:#"%#",[myArray objectAtIndex:row]];
// myAppDelegate *delegate = [[UIApplication sharedApplication] delegate];
// [delegate.myNavBarController pushViewController:addDetailVC animated:YES];
// self.addDetailVC.view.hidden =NO;
// [delegate.myNavBarController pushViewController:addDetailVC animated:YES];
}
If the view is being loaded OK when there are no UI elements, then most probably there must be something wrong at the interface builder side of things. Probably, an outlet/IBAction was defined and it can no longer be found.
The best thing to do is to open the 'Console' application (comes default in a Mac). Then, run your simulator and let the application crash. The Console will let you know what went wrong and will probably provide the source of the error. You might be seeing something like this:
11-08-04 1:02:06 AM StackOverFlow[10840] ** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: '-[UIViewController _loadViewFromNibNamed:bundle:] loaded the "Detail" nib but the view outlet was not set.'*