views:

39

answers:

1

I've overridden drawLayer:inContext: on UINavigationBar in a category so that I can put a custom image up there. I hate it, but my client was adamant.

As a result, I've had to fall back to some pretty ugly hacks to get things up there. I had to put a new method in that category to put a title on the nav bar header, and I have to call it explicitly in -viewDidAppear.

I can live with that. The real problem is, when memory gets low, it appears that UINavigationBar is unloading its subviews, including my back button! I don't really know how to recover from that.

Here's my UINavigationBar category. I got this code from here on SO, I think; Core Graphics mostly just makes my head spin.

@implementation UINavigationBar (background)

- (void)drawLayer:(CALayer *)layer inContext:(CGContextRef)ctx
{
    if([self isMemberOfClass: [UINavigationBar class]]){
        UIImage *image = [UIImage imageNamed:@"top_bar.png"];
        //CGContextClip(ctx);
        CGContextTranslateCTM(ctx, 0, image.size.height - 20);
        CGContextScaleCTM(ctx, 1.0, -1.0);
        CGContextDrawImage(ctx, CGRectMake(0, 2, self.frame.size.width, self.frame.size.height), image.CGImage);
    }
}

-(void)customTitle:(NSString *)text
{
    UINavigationItem *top = self.topItem;
    [[top.titleView subviews] makeObjectsPerformSelector:@selector(removeFromSuperview)];

    UILabel *title = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 200, 40)];
    title.textAlignment = UITextAlignmentCenter;
    title.text = text;
    title.textColor = [UIColor blackColor];
    title.font = [UIFont boldSystemFontOfSize:16];
    title.backgroundColor = [UIColor clearColor];
    top.titleView = title;
    [title release];

}

Is there a simpler way? If not, how can I tell UINavigationBar, "Reload yourself with the subviews you're supposed to have"?

UPDATE: Tried overriding -drawRect instead. The code is simpler but the problem remains--in certain cases the back button vanishes. By the way, I'm assuming it's related to having received a low-mem warning. It only seems to happen after coming back from a trip through UIImagePicker, so maybe something happens in there to change things. Also I did have NSZombies enabled, and obviously turning that off changes the memory complexion significantly.

A: 

Why not override drawRect in your UINavigationBar category, rather than drawLayer:inContext:?

As far as I can remember, it's a pretty clean hack, and there is no need to provide a custom UILabel for your title.

Update: Your information about a memory warning makes more sense. Are you setting a custom back button? When a controller receives a memory warning, it ditches it's view if it's not on screen. There is a very good chance that this it happening with your navigation controller. If you are setting a custom back button in say, an init method, there will be no way for it to be re-added to the navigation item post memory warning purge.

Jerry Jones
Please see my update.
Dan Ray