I have a simple spritekit app, SKView on intialization shows a splash screen(scene), the user clicks on a button they are taken to the main game scene.
Everything works fine, but wanted to add iads to it, so I instantiated an adview in the main scene, and assign its delegate to the main scene.
The add appears fine, and I click on it, it properly shows the ad, but then I dismiss the ad, and when I do that the app goes back and looks like it reinitializes the entire SKVIEW which displays the Splash Scene, not the main scene which was paused in the delegate calls.
So, when the IAD is dismissed, what exactly are the callbacks back into the parent app, because its clear its not just the delegate methods, its going back and reinitializing the view etc. Basically where in my view do I need to trap its returning from a canceled ad and handle this case properly.
Sounds like you're running the scene in viewWillLayoutSubviews without checking whether a scene is already running. Make sure the launch code looks like this, or it will relaunch the starting scene whenever the viewWillLayoutSubviews method runs (it can and will be called multiple times, for example when rotating the device and apparently also when dismissing an ad):
-(void)viewWillLayoutSubviews
{
SKView* skView = (SKView*)self.view;
// only create/launch first scene when SKView has no running scene
if (skView.scene == nil)
{
// create and present scene here ...
}
[super viewWillLayoutSubviews];
}
Related
I'm using storyboard.
As I remeber (I worked with ios 4, long time ago=)) everytime, when View appears, calls
-(void)viewWillAppear:(BOOL)Animated {}
method.
Now this method doesn't call, if I press Home button and run app again.
How to fix it?
I need to update one UIView if it appears after home pressing.
The function viewWillAppear is not part of UIView. It is part of UIViewController.
It is called after the view controller's view has been loaded and just before it starts to transition onto screen.
If you create a subclass of UIView and put this function in it then it will never be called because it isn't supposed to be.
Edit
You are correct that viewWillAppear does not get called when the app is coming back from the background.
If you want to update a part of your app when this happens then you can do something in the AppDelegate.
I'd recommend not trying to store properties etc... in the AppDelegate though. You should do something like this...
- (void)applicationWillEnterForeground:(UIApplication *)application
{
// Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
// just pass the message on. In your view you will need to add an observer for this notification
[[NSNotificationCenter defaultCenter] postNotificationName:#"UpdateViewNotification" object:nil];
}
try this, call the super,
-(void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
}
I am developing a banking application and the client requirement is not to show/save the screen snapshot when app goes in the background (i.e., when home button is clicked).
I have added an overlay view in background method and removed that view when app again comes in the foreground. Its working perfectly fine when I click home button, wait for 1 or 2 secs and then again click home button twice.
My problem is: If I click home button once, wait for some milliseconds (just before the app icons visible)and then again click home button twice, then the screen snapshot is visible (in multitasker view).
When I analysed the issue, I came to know that my background delegate method doesn't get called in this scenario and hence, no overlay view is added in this case.
Steps to Reproduce:
Add An overlay view (with while color, lets say) in appDidEnterBackground Method of your application.
Add code for removing that overlay view in willEnterForeground Method.
Now, run your application.
Press Home button once.
Just after pressing home button once (and just before your application icon is visible), click home button twice so that you are able to see the Multitasker view.
Instead of your overlay view, you would be seeing the application screenshot there.
Expected Results:
The While overlay view should have been added, and you should have seen that instead of app snapshot.
Actual Results:
You are able to see the application screen shot in Multi tasker view
Version:
iOS 7 and above
I've created an app that does exactly what you want. I throw up the shield image view in applicationWillResignActive:
- (void)applicationWillResignActive:(UIApplication *)application {
// ...
self.shieldImageView = [[UIImageView alloc] initWithFrame:self.window.frame];
self.shieldImageView.image = [UIImage imageNamed:#"shieldimage"];
self.shieldImageView.contentMode = UIViewContentModeScaleAspectFit;
[self.window addSubview:self.shieldImageView];
// ...
}
and get rid of it in applicationDidBecomeActive:
- (void)applicationDidBecomeActive:(UIApplication *)application {
// ...
[self.shieldImageView removeFromSuperview];
self.shieldImageView = nil;
// ...
}
Similar to this question: Adding subview, gets delayed?
But I don't think you can pushViewController in a separate thread so is this really impossible?
Here is what I'm trying to do:
I have a TableView and when a cell is pressed, I want to call
[self.view addSubview:LoadingView]
to display an overlay with a spinner. Then I call
self.navigationController.navigationBar.hidden = NO;
[self.navigationController pushViewController:newGameViewController animated:YES];
However, the subview only displays for a split second (~1-4 seconds after the cell selection occurs while it waits for the new viewcontroller to initialize).
Is there any way to get some sort of loading indicator to occur at the instant the cell is selected?
Okay. What about this. In your didSelectRowAtIndexPath start your spinner (via addSubview ...) and start loading your stuff from the server. If that's finished remove the spinner an push your new view controller onto the stack. Make sure the user can't touch any other cell during that time. By the way. From a users perspective I'd find it mor intuitive if the new controller is loaded immediately and displays some waiting message.
Or the other way around: The newGameViewController displays the spinner and starts loading the data from the server in a background thread. When the data is complete, remove the spinner and display the data. That way the user could even go back if she doesn't want to wait.
You do not need to add code before pushing newGameViewController.
Inside viewDidLoad of newGameViewController, write the code of displaying spinner. To get the updated UI, just insert a delay before calling a web API.
inside GameViewController.m
-(void) viewDidLoad
{
[self.view addSubview:LoadingView];
[self performSelector:#selector(callWebAPI) afterDelay:0.1];
}
-(void) callWebAPI
{
//Handle network activity here..
}
I have been coding and testing an app which uses a navigation controller, tab bar and table views together as shown in this tutorial video:
I have also coded a MapView page which shows custom annotations. This seems to work fine in every version of the simulator I have tried it on. This morning I have finally got the app running on my Ipod Touch which runs OS 3.1.3 - everything works as expected except the map does not seem to allow user interaction at all. I cannot tap on annotations, the current location or move and zoom at all.
I have been through all the settings in the Interface Builder for the mapview, and made sure that all the 'User Interaction', 'Allow Multitouch' boxes have been ticked. This doesn't seem to change anything.
Any help greatly appreciated.
The Mapview is put into the view as follows:
// Grab the maps view controller ready for loading
MapView *childController = [[MapView alloc] initWithNibName:#"MapView" bundle:nil];
childController.title = #"View on Map";
// Push the new view controller onto the stack
[self.navigationController pushViewController:childController animated:YES];
[childController release];
childController = nil;
I've also tried running the view in a modal view controller just to see what would happen. The view was shown and any interaction didnt seem to work - with the exception of a small section at the bottom where I made the view itself slightly shorter so it would fit in above the tab bar. This section seems to have another map underneath my view which DOES respond to user interaction. So there is a 1cm or so block which does move - my view seems to stay static on top of it, though.
The view underneath does not appear to have any annotations or the current user location.
Ok I've solved this one:
In the mapview.m file where I set up the view and load the annotations, within the viewDidLoad function I had the following code:
- (void)viewDidLoad {
// More code before this..
[mapView addAnnotations: eventPoints];
// This is causing the problems on the ipod touch.
// The view is added ON TOP of the first map..
//[self.view addSubview:mapView];
self.view = mapView;
// More code after this..
}
Where mapView is
IBOutlet MKMapView *mapView;
Adding a subview on top of the current view didn't want to work. Actually setting the view to be the new updated view with annotations seems to work fine. It's still strange that the simulator would work and not the device in the first place though.
Hope this helps someone.
I'm working on a UINavigationController driven iPad app (testing in the simulator). There are only two UIViewControllers on the nav controllers stack. For demonstration, lets call them SetupController and ContentController. SetupController pushes a ContentController on the stack with
[self.navigationController pushViewController:contentController animated:YES];
While looking at the content, you can press the back button to go back to the setup controller. If the app is in portrait mode, things work correctly.
However, when the app is in landscape and I hit the back button, things go haywire. The view controller stack is updated properly (e.g. I see the SetupController's view), but the UINavigationBar is not updated properly. The UINavigation bar items associated with the ContentController are still displayed. To see the SetupCotroller's expected UINavigationBar items, I have to press the back button a second time, at which point the UINavigationBar animates to the correct state. Again, this only happens in landscape mode, portrait mode works perfectly.
As a test. In the [SetupController viewDidAppear:] method I have added the following debug output
if(self.navigationController.navigationBar.topItem != self.navigationItem) {
NSLog(#"wrong nav item!");
} else {
NSLog(#"correct nav item!");
}
I get the "wrong" message whenever the simulator is in landscape mode, and never when it is in portrait mode. I've tried removing all viewDidAppear: messages from both ViewControllers and any instances where I'm modifying their navigation items or the navigation bar itself.
Any thoughts? I'm assuming I'm doing something wrong here, but this sure feels like a bug to me.
I ran into the same problem. It's weird, but you need to make sure all of the view controllers in the stack have the following implemented (even if everything is displaying correctly rotated):
(BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
return YES;
}