3

I have created a kiosk application with a main view and a modal view with an image carousel as a screensaver. This modal view slides down whenever the screen is touched.

If the devices are left alone for a very long time (overnight) with the app running, the screen gets redraw problems when the screensaver modal animates away. It looks like the os has nothing to draw where the background image of the main screen is. The controls and text on the main screen draw like they should, only the background image is replaced by artifacts of the hiding animation from the modal. This happens on two devices (iPad 2 3G 16GB). This only occurs if the app has been running for a very long time, and it does not matter whether the screen is on or not. The background UIImageView in question is a vanilla UIImageView with no properties other than the "Image" changed.

It looks like this (client logo and some text blurred out): http://tinypic.com/view.php?pic=2qx47bt&s=6

Any ideas of what could be wrong and how to fix it?

Edit: Here is the code hiding the screensaver. Very standard, no hocus pocus.

- (void)hideScreenSaver {
    dispatch_async(dispatch_get_main_queue(), ^{
        if (![[[self mainViewController] presentedViewController] isKindOfClass:[UINavigationController class]]) {
            [[self mainViewController] dismissModalViewControllerAnimated:TRUE];
        }
    });
}

The screensaverViewController is created in - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions (in the main thread)

[[GMAppManager sharedManager] setScreenSaverViewController:[[AAScreenSaverViewController alloc] initWithNibName:@"AAScreenSaverViewController" bundle:nil]];
Maciej Swic
  • 11,139
  • 8
  • 52
  • 68
  • Can you post some code related to the animations? – Marcelo Apr 09 '13 at 08:52
  • 2
    @MarceloFabri I added some code above but there is nothing strange going on there. – Maciej Swic Apr 09 '13 at 08:58
  • why do you need dispatch_async? what happens if you don't use it? – meronix Apr 09 '13 at 09:05
  • 2
    @meronix Because `hideScreenSaver` may be called from other threads than main and UI operations are not allowed outside main. So i can't really remove it, and it **shouldn't** be an issue. – Maciej Swic Apr 09 '13 at 10:18
  • 1
    Are you sure the line with the dismiss is executed? I would first have a look at memory management, maybe some view are not retained anymore. We would need more code: property, what is self.mainVC? – Geraud.ch Apr 11 '13 at 09:23
  • Yes, it makes the screensaver go away, and that's when the issue occurs. App running with screensaver for a prolonged period of time, and then the issue shows when the screensaver is dismissed. self.mainVC is a strong property and it's never released. The image view in the background that seems like it's never redrawn is part of a nib. You think this background UIImageView is unloaded and fails to reload? It should be recreated from the nib in that case, the image is set in the nib, no code needed to create the view. – Maciej Swic Apr 11 '13 at 09:26
  • can you try to set the animation as false just to check if the animation is the problem? –  Apr 11 '13 at 09:48
  • 1
    Did you try "simulate memory warning" in the simulator? Just in case it's related to the image being let go off after a memory warning due to a small memory leak adding up over the long running time – baris Apr 11 '13 at 12:16
  • @baris Tried it on the simulator, didn't cause the problem. Maybe it needs to be an actual device. Is there a way to force a memory warning on an actual device without leaving the app? Because if i leave the app iOS will probalby kill it alltogether. I only want it to potentially unload the UIImageView. – Maciej Swic Apr 11 '13 at 15:22
  • I don't think there is. Well.. You can always create a bunch of large objects :) It's unlikely the memory warning happening on the device would have a different outcome though. – baris Apr 11 '13 at 20:38
  • You might also try changing dispatch_async to dispatch_sync, just in case there is a synchronization problem related to the called of -hideScreenSaver (or maybe you can post some code from the caller of that method). You explained why you need to dispatch on the main thread, but I don't think you need dispatch_async specifically. – baris Apr 11 '13 at 20:43
  • @baris dispatch_sync is dangerous here. It would cause the whole app to freeze (deadlock) when `hideScreenSaver` is called from the main thread. – Felix Apr 11 '13 at 23:05
  • This might be obvious, but do you have backgroundColor/opaque properties setup properly on all the views involved? – proxi Apr 12 '13 at 08:35
  • The backgroundColor is not set because the background for the entire screen is an image, the one not redrawing properly. I saw opaque was checked for some transparent views, i unchecked that and will see if the issue comes back. Thanks for the suggestion. – Maciej Swic Apr 12 '13 at 09:50
  • @phix23 You're right, I didn't consider he might be calling it from the main thread as well. I guess he could still check with [NSThread isMainThread] though and only use dispatch when it's not the main thread. Not that I have any reason to believe this will solve his problem – baris Apr 12 '13 at 14:02

2 Answers2

2

`I have absolutely had this problem at it was simply a leak on a uikit resource. Run build and analyze and fix leaks. Also set break points on all your deallocs and make sure they are being called. A dealloc will not get called if even a single reference to a part of the class is retained and not released. Check also all objects that you pass a parameter:self. These references to self if the object using self is not release will also block dealloc. Autorelease pools will not drain if the loop is tight. Try using explicit releases. Delgates need to be assign and not retain.

Post up some more errors and questions and I take a look. You have a cool project.

nolimitsdude
  • 631
  • 5
  • 9
  • Unfortunately I'm using ARC here so i never explicitly dealloc/release anything. How do i apply your answer for ARC? – Maciej Swic Apr 12 '13 at 07:22
  • Even if you are using ARC, the memory management continue to use alloc/release (but this is done automatically). Object may not be released correctly if "something strange" is happening in your code. (happened just yesterday in one of my projects :-) Just override the dealloc method of your objects (omitting the [super dealloc] method) and set a breakpoint. This will let you know if the objects are correctly deallocated after use. Moreover, use instruments with the allocation tool, to monitor the memory usage. – LombaX Apr 15 '13 at 12:56
  • -(void)dealloc{ NSLog(@"Hey we are free from memory, now clean up any CF retains") } // Break point that and is should get hit, if its not then you are still having a strong reference to your object. – nolimitsdude Apr 16 '13 at 10:29
2

When you say

The background UIImageView in question is a vanilla UIImageView with no properties other than the "Image" changed.

Can you make sure that You are clearing that UIImageView first, before changing the Image

I am sure that you must know. But, just in case, Can you try it out:

youeImageView.image = nil and then setting some other image?

By seeing the image you have provided, the reason doesn't seem to be anything else, IMHO.

viral
  • 4,168
  • 5
  • 43
  • 68
  • 2
    Thanks, Ill try that and report back. – Maciej Swic Apr 12 '13 at 07:30
  • Make sure delegates are not strong. Inspect all properties with strong references and make sure you do not have a property retaining a strong. One should be weak so it can be released, and the allow the strong one to also be released. When the class is removed form memory. Check your allocations in instruments and see what is still alive after running. If you thing all should be out of memory after the screen saver is run and they are still present something is holding a strong reference. – nolimitsdude Apr 12 '13 at 21:27
  • You could also to a test to see if you load the class and then exit with out keeping a strong reference to the class should be gone. View status in instruments for objects still alive. – nolimitsdude Apr 12 '13 at 21:29