My app works great on the emulator, but not so good on the phone. Two issues:
1 - I have a UIScrollView that contains a UIImageView, on the phone, sometimes the UIImageView never paints itself, so that area shows the results of a table view that animated out to reveal it. This never happens in the emulator
2 - the application is prone to crashing, and my logging makes me think it's within this code:
// called after this controller's view will appear
- (void)viewWillAppearBOOL)animated
{
NSLog(@" DCOImageDisplayController - (void)viewWillAppearBOOL)animated called" );
// for aesthetic reasons (the background is black), make the nav bar black for this particular page
self.navigationController.navigationBar.barStyle = UIBarStyleBlackOpaque;
// match the status bar with the nav bar
[UIApplication sharedApplication].statusBarStyle = UIStatusBarStyleBlackOpaque;
visible = YES;
currentIndex = 0;
I've tried adding the SegmentedControl in other places, so it doesn't get created every time, but I've been unable to make this work. Does anyone have any suggestions ?
Actually, while I'm not sure this is not an issue, as I've made this view a member variable, I am wondering if it being a member is why my images never update, once the first has been set ( although this doesn't make a whole lot of sense, none of this makes sense to me ). However, when the app crashes, this method actually finishes ( I added some logging to say the method was done ) and then the app freezes. It works fine on the emulator, so I am not sure what is going wrong.
Last edited by cgraus; 10-11-2008 at 05:14 PM.
Reason: Adding some detail
It strikes me that this is a bad place to add your UISegmentedControl, since viewWillAppear: can get called multiple times for a particular UIViewController - for example if your view is covered and then exposed again, it will be called again.
Normally, I would think that you would do this in your "initWithNibName:bundle:" routine after having called the "super" version thereof.
That being said, it strikes me as a slightly odd user interface to have a UISegmentedControl in the nav bar's right button. But, then, who am I to say what's "good" and what's "bad".
Another nit - you've called "alloc" to create both the UISegmentedControl and the UIBarButtonItem, but haven't made a corresponding call to "release" in either case.
So, when I create something and add it to the view, I have to release it, and the view that holds it adds it's own reference ?
Exactly.
With very, very few exceptions, any time you say
Code:
anObject.property = object;
the code for "property" retains the object.
Basically, any class that wants an object to persist retains it itself, just in case nobody else wanted to hold onto it. Thus, for example, you could create a button, add it as a subview of your view and then release it if you didn't need to manipulate it any further. The view retains it when you add the button to the view, so the button doesn't get destroyed when you release it, but the only reference to the object would be that of the view, and when the view got released, it would then release the button and the button would thus get destroyed. Very elegant. On the other hand, if you wanted to hold onto the button yourself, you would typically do:
then the "self.myButton = button" line will add a reference (balanced by the "release" that you would code into your "dealloc" routine) because of the nature of the code that the compiler generates for you in the "@synthesize" line, the view has one, and the explicit release still balances out your "alloc".
The "rule" basically says that you have to release the object if
(a) you were the one to call "alloc"
(b) it was created using a method named "create"
Otherwise, you should not, unless you explicitly called "retain".
What's happening is that the imageWithContentsOfFile: routine builds the image for you, but (since it doesn't have "create" in its name) it also calls "autorelease" on the image for you. This will cause the autorelease pool to call "release" on the returned object when this particular event is over. If you call "release" manually, then the later "release" from the autorelease pool is one too many.
Thus, an object built this way has an "effective" retain count of zero. (If you ask the object for its retain count, it will report "1", but you have to factor in the pending "release" call from the autorelease pool.) Your assignment to [self setImage:image] presumably adds a "retain", so at the end of the event processing, the autorelease pool's "release" doesn't deallocate the object. With your extra "release", however, you've "undone" the retain in your "setImage" method, and thus the "release" in the autorelease pool deallocates the image. "self" is left with a pointer to a dead object.
*grin* well, to be honest, this aspect of things has been the hardest learning curve for me, and it does seem 'twisty', but that's fine, I appreciate your explanation and I think I am finally understanding it. Which is great, b/c when I finish this iPhone app, I start working on my first Mac app, also in OC.