GLKViewController and GLKView - Rendering nothing the second time created - ios

I have a MainMenuViewController and a GameViewController which is a GLKViewConrtroller.
The first time I go from the main menu to the GameViewController everything is rendered fine. If I go back to the main menu, the GameViewController and its view get dealloced (I logged it).
When now going back to the game, I see a blank screen, nothing gets rendered OpenGL-wise. The overlay test menu with UIKit is still there.
Thisis how I tear down OpenGL in the GameViewController's dealloc method, the last five lines were added as tries to make it work, so it doesn't work with or without them.
- (void)tearDownGL {
[EAGLContext setCurrentContext:self.context];
glDeleteBuffers(1, &_vertexBuffer);
glDeleteVertexArraysOES(1, &_vertexArray);
self.effect = nil;
_program = nil;
glBindVertexArrayOES(0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindTexture(GL_TEXTURE_2D, 0);
[EAGLContext setCurrentContext: nil];
}

I think that the problem is that you are not using a sharegroup - a place where OpenGL can share textures and shaders between contexts?
Here is code that will create a sharegroup that all your GLKViewController 's subclass. If you have multiple subclasses you will have to do something to make the shareGroup global, if that's appropriate.
- (void)viewDidLoad
{
[super viewDidLoad];
// Create an OpenGL ES context and assign it to the view loaded from storyboard
GLKView *view = (GLKView *)self.view;
// GLES 3 is not supported on iPhone 4s, 5. It may 'just work' to try 3, but stick with 2, as we don't use the new features, me thinks.
//view.context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES3];
//if (view.context == nil)
static EAGLSharegroup* shareGroup = nil;
view.context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2 sharegroup:shareGroup];
if (shareGroup == nil)
shareGroup = view.context.sharegroup;
...

Related

Cocos2d black screen after app archive

I have cocos2d setup as a sub-project in my iOS app, running the latest release (3.5) and targeting iOS versions 9.0+. The problem I'm having is that the cocos2d screen is black when I download and install the app from TestFairy. I have debugged it both on the simulator and on real device and the cocos2d scene loads properly.
It's a simple finger painting app and it's all based on UIKit. Cocos2d is added to a ViewController in the standard way. The relevant code is:
CCDirector *director = [CCDirector sharedDirector];
// If the director's OpenGL view hasn't been set up yet, then we should create it now. If you would like to prevent this "lazy loading", you should initialize the director and set its view elsewhere in your code.
if ([director isViewLoaded] == NO) {
director.view = [self createDirectorGLView];
[self didInitializeDirector];
}
else {
director.view.frame = [self getCanvasFrame];
[director.view setNeedsLayout];
[director.view layoutIfNeeded];
}
director.delegate = self;
// Add the director as a child view controller.
[self addChildViewController:director];
// Add the director's OpenGL view, and send it to the back of the view hierarchy so we can place UIKit elements on top of it.
[self.targetView addSubview:director.view];
[self.targetView sendSubviewToBack:director.view];
// Ensure we fulfill all of our view controller containment requirements.
[director didMoveToParentViewController:self];
The createDirectorGLView is as follows:
- (CCGLView *)createDirectorGLView {
_glView = [CCGLView viewWithFrame:[self getCanvasFrame]
pixelFormat:kEAGLColorFormatRGB565
depthFormat:0
preserveBackbuffer:NO
sharegroup:nil
multiSampling:NO
numberOfSamples:0];
return _glView;
}
I also have a scene which contains the CCNode that handles the drawing. It is created like this:
#implementation IntroScene
- (id)init:(CGRect)frame {
self = [super init];
if (self) {
_canvas = [[LineDrawer alloc] init];
_canvas.contentSize = CGSizeMake(frame.size.width, frame.size.height);
_canvas.position = CGPointZero;
_canvas.anchorPoint = CGPointZero;
[self addChild:_canvas];
}
return self;
}
#end
I can't get access to the console logs for some reason while the app is running from TestFairy so I can't say what's going on there. When I debug from Xcode however, everything looks normal and the cocos2d canvas is loading/working just fine. I have a feeling it might be something to do with the way the project is archiving but I'm not sure. Any ideas?
Edit
So I managed to reproduce it in Debug mode on a device and I saw a few errors which I think are related to TestFairy's screen recording using OpenGL and cocos2d.
2016-06-06 12:49:56.362 GraffiTab[5654:2941813] *** Assertion failure in -[CCRenderStateGL initWithBlendMode:shader:shaderUniforms:copyUniforms:], /Users/georgichristov/Documents/Workspace/Examples/GraffiTab/GraffiTab-iOS/GraffiTab/ExternalLibs/Cocos2d/cocos2d/CCRendererBasicTypes.m:356
2016-06-06 12:49:56.362 GraffiTab[5654:2941813] [visit] error CCRenderState: Blending mode is nil
2016-06-06 12:49:56.705 GraffiTab[5654:2941813] TestFairy: Initializing SDK version 1.7.6 (20160531-772d18b7)
2016-06-06 12:49:58.057 GraffiTab[5654:2941813] TestFairy: Session started successfully
2016-06-06 12:49:58.929 GraffiTab[5654:2941813] Please remove uses of SCRCException!

How to stop iOS EAGLContext's memory from growing?

In this super simple app that uses a GLKViewController to display a red screen the memory keeps growing.
ViewController.h:
#import <UIKit/UIKit.h>
#import <GLKit/GLKit.h>
#interface ViewController : GLKViewController
#end
ViewController.m:
#import "ViewController.h"
#interface ViewController ()
#end
#implementation ViewController {
EAGLContext* context;
}
- (void)viewDidLoad {
[super viewDidLoad];
context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];
GLKView* view = (GLKView*)self.view;
view.context = context;
view.drawableDepthFormat = GLKViewDrawableColorFormatRGBA8888;
[EAGLContext setCurrentContext:context];
self.preferredFramesPerSecond = 60;
}
- (void)glkView:(GLKView *)view drawInRect:(CGRect)rect {
glClearColor(1.0f, 0.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
}
#end
For each frame 9*64 bytes is allocated and never freed as seen in this image (note that the transient count is 0 for IOAccellResource):
This is what the allocation list and stacktrace looks like:
The memory "leak" is small but it still managed to use up 6.5 MB despite only running for less than 3 minutes.
Is there a bug in the EAGLContext or is there something I can do about this? I have noticed (I'm new to iOS development) that other parts of Apple's API uses zone allocators and the memory usage keeps growing when it really should have been in some kind of steady state mode. That makes me think I have missed something (I have tried to send it LowMemory but nothing happen).
So from your comment you say that you are using some other code that is written in C++ and basically all you need is the connection to the actual buffer to be presented. I will assume none of that "C++" code you mentioned is inflating your memory and you have actually try to create a new application only adding the code you posted just to be 100% sure...
To migrate off the GLKit is then very easy for you. Simply subclass the UIView which will be used to drawing and add a few methods:
This needs to be overridden so you can get the render buffer from the view
+ (Class)layerClass {
return [CAEAGLLayer class];
}
The context is already done correctly and needs to be used.
You need to setup the buffers manually. I use a custom class but I believe you will be able to see what is going on here and possibly remove the code you don't need.
- (void)loadBuffersWithView:(UIView *)view
{
self.view = view;
CAEAGLLayer *layer = (CAEAGLLayer *)view.layer;
layer.opaque = YES;
if ([[UIScreen mainScreen] respondsToSelector:#selector(displayLinkWithTarget:selector:)]) {
layer.contentsScale = [UIScreen mainScreen].scale;
}
GLuint frameBuffer; // will hold the generated ID
glGenFramebuffers(1, &frameBuffer); // generate only 1
self.frameBuffer = frameBuffer; // assign to store as the local variable
[self bindFrameBuffer];
GLuint renderBuffer; // will hold the generated ID
glGenRenderbuffers(1, &renderBuffer); // generate only 1
self.renderBuffer = renderBuffer; // assign to store as the local variable
[self bindRenderBuffer];
[self.context.glContext renderbufferStorage:GL_RENDERBUFFER fromDrawable:layer];
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, self.renderBuffer);
GLint width, height;
glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_WIDTH, &width);
glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_HEIGHT, &height);
self.bufferSize = CGSizeMake(width, height);
glViewport(0, 0, width, height);
[GlobalTools framebufferStatusValid];
[GlobalTools checkError];
}
On present you need to call presentRenderbuffer on your context with the appropriate render buffer id.
Rest of your code should be the same. But remember to also tear down the openGL when you do not need it and possibly explicitly delete all the buffers that were generated on the GPU.
I printed out the amount of resident memory to the screen and noticed that the memory didn't increase when the device was disconnected from the debugger.
It turns out that using the "Zombie instrument" was causing this... I swear that I saw the memory increase in the memory view of the debugger too, but now I can't repeat it (haven't changed anything in the scheme).

Can't show the scene second time in Cocos3D

I have a viewController with cocos scene which I push in my navigation controller. In this view controller I have this methods:
-(void) viewDidLoad
{
[super viewDidLoad];
[_cc3FrameView addSubview: [self createGLView]];
CC3Backgrounder.sharedBackgrounder.shouldRunTasksOnRequestingThread = YES;
}
- (void) viewWillAppear:(BOOL)animated
{
if (!sceneInitialized) {
sceneInitialized = YES;
[CCDirector.sharedDirector runWithScene: [[self makePanoramaScene] asCCScene]];
} else {
[CCDirector.sharedDirector resume];
}
[CCDirector.sharedDirector startAnimation];
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[[self runningPanoramaScene] sceneWillShow];
});
}
-(AxPanoramaScene *)runningPanoramaScene
{
CCScene *scene = [CCDirector.sharedDirector runningScene];
AxPanoramaLayer *panoramaLayer = [scene.children lastObject];
AxPanoramaScene *panoramaScene = (AxPanoramaScene *)panoramaLayer.cc3Scene;
return panoramaScene;
}
-(void)viewWillDisappear:(BOOL)animated
{
[CCDirector.sharedDirector pause];
}
While I push this controller - everything is working, but when I pop this controller and push it again - I got the bright pink screen and continuos messages in log:
2014-12-12 19:30:06.447 UniversalMapExample[2262:258353] cocos2d: animation started with frame interval: 60.00
2014-12-12 19:30:06.452 UniversalMapExample[2262:258353] cocos2d: surface size: 768x973
OpenGL error GL_INVALID_OPERATION detected at -[CCES2Renderer resizeFromLayer:] 161
2014-12-12 19:30:06.452 UniversalMapExample[2262:258353] Failed to make complete framebuffer object 0x8219
2014-12-12 19:30:06.453 UniversalMapExample[2262:258353] cocos2d: surface size: 768x973
OpenGL error GL_INVALID_OPERATION detected at -[CCES2Renderer resizeFromLayer:] 161
2014-12-12 19:30:06.453 UniversalMapExample[2262:258353] Failed to make complete framebuffer object 0x8219
OpenGL error GL_INVALID_OPERATION detected at -[CCRenderer(NoARCPrivate) setRenderState:] 232
OpenGL error GL_INVALID_OPERATION detected at -[CCRenderer(NoARCPrivate) setRenderState:] 232
OpenGL error GL_INVALID_OPERATION detected at -[CCRenderer(NoARCPrivate) setRenderState:] 232
OpenGL error GL_INVALID_OPERATION detected at -[CCRenderer(NoARCPrivate) setRenderState:] 232
[***GL ERROR***] GL_INVALID_VALUE: Numeric argument is out of range from glUseProgram(15).
[***GL ERROR***] GL_INVALID_OPERATION: Operation not allowed in current state from glUniform3fv(7, 4, (0.329, 0.944, 0.000)) setting u_cc3LightSpotDirectionModel.
[***GL ERROR***] GL_INVALID_OPERATION: Operation not allowed in current state from glUniformMatrix4fv(12, 1, GL_FALSE,
[0.021050, -0.007339, -0.000000, 0.210503
0.000000, -0.000000, 0.017596, -0.977556
0.005937, 0.017031, 0.000000, -0.660065
0.005926, 0.016997, 0.000000, 1.339256]) setting u_cc3MatrixModelViewProj.
How to correctly push the controller with cocos scene several times? I changed the example from cocos sources to this code. What am I doing wrong here? Please, note - that my controller is not CCDirector - it just contains a view with Cocos scene - the realization is like CC3DemoMultiScene. Thanks!
Remember that the CCDirector is a UIViewController, but it is also a singleton, which give it some unique nuances.
For example, you seem to be invoking the createGLView method every time you want to replace your controller. If it follows the CC3DemoMultiScene design, this will try to recreate another CCGLView before the old one has been released from the CCDirector singleton.
It's generally best to treat the CCDirector and the CCGLView that you create for it as a self-contained reusable unit. As you pop the containing controller, leave everything as is, and simply add and remove the CCGLView from the view hierarchy each time.
...Bill
This is a copy/paste from my blog where I covered a similar issue. The only difference is that I wanted full UIKit integration. I did have the problem where the 2nd time through. Perhaps it will help you.
http://www.notthepainter.com/full-cocos2d-uikit-integration/
I was working on a cocos2d based tapping game and I wasn’t able to run my game twice. It was clear that I wasn’t shutting the 1st game down correctly or building the 2nd game correctly, or both!
There are a lot of tutorials on the web out there teaching you how to add UIKit buttons to your Cocos2D app, or how to launch Cocos2D from your UIKit based app. But I needed to do both. I wanted a UIViewController under my game and UIKit widgets on top of my game. I spent a lot of time reading and this is what I came up with.
First, building the Xcode project was a nightmare. I eventually used the cocos2d/box2d template and then ripped out the files I didn’t needed, and added all my original files back in. The AppDelegate.m file looks just like a non-cocos2d app should look. This goes against the grain of many of the tutorials which advise you to build your cocos2d environment in the AppDelegate. I struggled with that, didn’t have luck for most of a Friday and then on Monday I put in a Cocos2DSingleton and it pretty much ran first time.
Here is my GameViewController’s viewDidLoad method:
- (void)viewDidLoad
{
[super viewDidLoad];
[[UIApplication sharedApplication] setStatusBarHidden:YES withAnimation:NO];
TTCocos2DSingleton *shared = [TTCocos2DSingleton sharedCocos2D];
CCGLView *glView = [shared currentGLView];
[self.view insertSubview:glView atIndex:1];
}
There are a view things to note. GameViewController has game UIButtons, score UILabels, and other game type of UI widgets. This lets me do a lot of the game controls in Interface Builder, not laying them out by hand. Notice I hide the status bar since the game is full-screen.
I get my cocos2d instance via the singleton, get its glView and insert this into the GameViewController’s view at index 1. This puts it below all the game controls. I’ll show you the sharedCocos2D method later, lets look at viewWillAppear.
- (void) viewWillAppear:(BOOL)animated
{
if(![[CCDirector sharedDirector] runningScene]){
CCScene *scene = [MyGameLayer scene];
myGame = [MyGameLayer node];
myGame.delegate = self;
[scene addChild: myGame];
[[CCDirector sharedDirector] runWithScene:scene];
} else {
// we have a scene already, replace the original to get a new game
[[CCDirector sharedDirector] startAnimation];
CCScene *scene = [MyGameLayer scene];
myGame = [MyGameLayer node];
myGame.delegate = self;
[scene addChild: myGame];
[[CCDirector sharedDirector] replaceScene:scene];
}
}
Notice how we treat the first run differently from the second run. For the second, and subsequent runs, we replace the scene with a new one. This avoids all “restarting” problems. Also notice that I set a delegate. I use a delegate protocol to communicate between my game layer and my UIViewController.
My singleton pattern comes from the Duck Rowing blog which I must admit is a pretty awesome name for a blog. I’m not going to show all the singleton code here, this blog is about cocos2d, but here is how I build my cocos2d environment.
+ (TTCocos2DSingleton *) sharedCocos2D;
{
static dispatch_once_t onceQueue;
dispatch_once(&onceQueue, ^{
if (sharedInstance) {
return;
}
sharedInstance = [[TTCocos2DSingleton alloc]init];
// Create an CCGLView with a RGB565 color buffer, and a depth buffer of 0-bits
sharedInstance->glView = [CCGLView viewWithFrame:[[UIScreen mainScreen] bounds]
pixelFormat:kEAGLColorFormatRGB565 //kEAGLColorFormatRGBA8
depthFormat:0 //GL_DEPTH_COMPONENT24_OES
preserveBackbuffer:NO
sharegroup:nil
multiSampling:NO
numberOfSamples:0];
[sharedInstance->glView setMultipleTouchEnabled:YES];
[sharedInstance setupDirector];
});
return sharedInstance;
}
The singleton sets up the CCGLView, enables multi-touch and then sets up the director. (I put that in another method since I thought, erroneously, that I’d need to call it elsewhere. Turns out I didn’t need to.)
- (void)setupDirector
{
CCDirectorIOS *director = (CCDirectorIOS*) [CCDirector sharedDirector];
[director setView:glView];
[director enableRetinaDisplay:YES];
director.wantsFullScreenLayout = YES;
[director setDisplayStats:NO];
[director setAnimationInterval:1.0/60];
}
And in setupDirector we set the usual suspects needed for a cocos2d app. Now the game can be played multiple times, I have a full UIViewController/UINavController underneath it, and I have UIKit widgets on top of my game. Nirvana.

OpenGL ES 2.0 Invalid drawable error

I'm trying to set up openGL for an iOS app I am building and I am receiving the following error:
-[EAGLContext renderbufferStorage:fromDrawable:]: invalid drawable
Here is a part of my code, located within a UIViewController class:
#implementation MyViewController
{
CAEAGLayer *_eaglLayer;
EAGLContext *_context;
GLuint _colorRenderBuffer;
}
+(Class)layerClass
{
return [CAEAGLLayer class];
}
-(void)setup
{
_eaglLayer = (CAEAGLLayer *)self.view.layer;
_eaglLayer.opaque = YES;
EAGLRenderingAPI api = kEAGLRenderingAPIOpenGLES2;
_context = [[EAGLContext alloc] initWithAPI:api];
glGenRenderbuffers(1, &_colorRenderBuffer);
glBindRenderbuffer(GL_RENDERBUFFER, _colorRenderBuffer);
[_context renderbufferStorage:GL_RENDERBUFFER fromDrawable:_eaglLayer];
}
How do I fix this error?
Try making the context current after creating it. I believe that does not happen automatically despite all the "magic" that some of these helper classes do for you.
_context = [[EAGLContext alloc] initWithAPI:api];
[EAGLContext setCurrentContext: _context];
The first line is what you already have, the second line is the one you add.

Am I missing something with ARC?

I'm developing a large scale application for iOS 5 using ARC in xcode. The system seems to work well except for when I'm trying to deallocate one of my interfaces. I'm using a framework called WhirlyGlobe to create a 3D interactive globe in the first view controller.
When I switch view controllers (between the 4 I have), I notice that the memory being used for the view controller with the globe isn't being released. All the other view controllers (only using simple views and images) release their memory fine - But the globe stays resident, or so it seems. When navigating back to the globe, I get almost a 10mb jump in memory due to 1mb allocations in "glsmLoadTextureLevelBuffer".
To get on with my question - Is there anything more I can do, with ARC active, to help release my objects? I've noticed my viewDidUnload and dealloc methods are not being called at all, and that the only way I can get anything to fire is using viewDidDisappear (which is not ideal obviously) - See below:
- (void)clear
{
[[NSNotificationCenter defaultCenter] removeObserver:self];
if (self.layerThread)
{
[self.layerThread cancel];
while (!self.layerThread.isFinished)
[NSThread sleepForTimeInterval:0.001];
}
self.glView = nil;
self.sceneRenderer = nil;
if (theScene)
{
delete theScene;
theScene = NULL;
}
self.theView = nil;
self.texGroup = nil;
self.layerThread = nil;
self.earthLayer = nil;
self.vectorLayer = nil;
self.labelLayer = nil;
self.interactLayer = nil;
self.pinchDelegate = nil;
self.panDelegate = nil;
self.tapDelegate = nil;
self.longPressDelegate = nil;
self.rotateDelegate = nil;
}
- (void)viewDidDisappear:(BOOL)animated {
NSLog(#"dealloc - viewDidDisappear");
[self clear];
}
I'm setting everything I no longer need to nil. Is this the best practise?
The globe setup code:
[super viewDidLoad];
AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
// Set up an OpenGL ES view and renderer
EAGLView *ev = [[EAGLView alloc] initWithFrame:CGRectMake(0, 0, 824, self.view.frame.size.height)];
self.glView = ev;
self.sceneRenderer = [[SceneRendererES1 alloc] init];
UIColor *whiteC = [UIColor whiteColor];
[sceneRenderer setClearColor:whiteC];
glView.renderer = sceneRenderer;
glView.frameInterval = 2; // 60 fps (2)
[self.view addSubview:glView];
self.view.backgroundColor = [UIColor blackColor];
self.view.opaque = YES;
self.view.autoresizesSubviews = YES;
//glView.frame = self.view.bounds;
glView.frame = CGRectMake(275, GLOBE_HEIGHT_FIX, 768, SCREEN_HEIGHT+STATUS_BAR_HEIGHT); // was 260 x
glView.backgroundColor = [UIColor whiteColor];
self.view.backgroundColor = [UIColor whiteColor]; // red for debug
// Create the textures and geometry, but in the right GL context
[sceneRenderer useContext];
self.texGroup = [[TextureGroup alloc] initWithInfo:[[NSBundle mainBundle] pathForResource:#"bdGlobe_info" ofType:#"plist"]];
// Need an empty scene and view
theScene = new WhirlyGlobe::GlobeScene(4*texGroup.numX,4*texGroup.numY);
self.theView = [[WhirlyGlobeView alloc] init];
[theView setFarPlane:5.0];
[theView setHeightAboveGlobe:GLOBE_HEIGHT_VIEW];
if (globeShouldAnimate) glView.alpha = 1.0;
// Need a layer thread to manage the layers
self.layerThread = [[WhirlyGlobeLayerThread alloc] initWithScene:theScene];
// Earth layer on the bottom
self.earthLayer = [[SphericalEarthLayer alloc] initWithTexGroup:texGroup];
[self.layerThread addLayer:earthLayer];
// Set up the vector layer where all our outlines will go
self.vectorLayer = [[VectorLayer alloc] init];
[self.layerThread addLayer:vectorLayer];
// General purpose label layer.
self.labelLayer = [[LabelLayer alloc] init];
[self.layerThread addLayer:labelLayer];
self.interactLayer = [[InteractionLayer alloc] initWithVectorLayer:self.vectorLayer labelLayer:labelLayer globeView:self.theView
countryShape:[[NSBundle mainBundle] pathForResource:#"10m_admin_0_map_subunits" ofType:#"shp"]
oceanShape:[[NSBundle mainBundle] pathForResource:#"10m_geography_marine_polys" ofType:#"shp"]
regionShape:[[NSBundle mainBundle] pathForResource:#"10m_admin_1_states_provinces_shp" ofType:#"shp"]];
self.interactLayer.maxEdgeLen = [self.earthLayer smallestTesselation]/10.0;
[self.layerThread addLayer:interactLayer];
// Give the renderer what it needs
sceneRenderer.scene = theScene;
sceneRenderer.view = theView;
// Wire up the gesture recognizers
self.panDelegate = [PanDelegateFixed panDelegateForView:glView globeView:theView];
self.tapDelegate = [WhirlyGlobeTapDelegate tapDelegateForView:glView globeView:theView];
self.longPressDelegate = [WhirlyGlobeLongPressDelegate longPressDelegateForView:glView globeView:theView];
// Kick off the layer thread
// This will start loading things
[self.layerThread start];
You can use the allocations instrument for this. Using heap shot, you can mark the heap at various points in the lifetime of your application and compare the object graph that constitutes the current allocations in memory at the point of each snapshot. That should help you narrow down what's being retained and by whom.
This is anecdotal, but COULD be a similar situation.
I just had a situation where my objects were not getting released ever, in ARC, even though they were accessed in a static way (e.g., [SingletonThing instance].thing) because the autorelease pool wasn't draining. The reason for this was a bizarre endless loop that runs on its own thread. Putting a separate #autorelease block for the enclosing code.
On the other hand, even if one of your (or the libs) object has the UIView as a subview, I think your UIViewController will never viewDidUnload and therefore never dealloc. I have to check this empirically.
make sure your -(void)viewDidDisappear:(BOOL)animated is invoked.
if you use
[self.view addSubview:yourViewController.view];
and
[yourViewController.view removeFromSuperview];
then viewDidDisappear: and viewDidAppear: will not be invoked
these callback will only be invoked
when you use presentViewController: in IOS 5
or presentModalViewController:
and dismissViewControllerAnimated: in IOS 5
or dismissModalViewControllerAnimated:
or use UINavigationController to present and dismiss your viewController
I found the problem after using heap shots (thanks to Mark Adams) - Turns out I wasn't making a couple of delegates weak entities, so they weren't being released when changing the view controller. Default strong delegates stay resident.
Thanks to all the suggestions, they all helped point me in the right direction :)

Resources