Why my Objective-C code throws Exception? - iphone

I am new to Objective-C and i'm trying to program an iPhone App.
This is my code :
Head File:
#import <UIKit/UIKit.h>
#interface TutorialViewController : UIViewController{
UILabel *labelText;
UIImageView *imageView;
}
#property(nonatomic,retain) IBOutlet UILabel *labelText;
#property(nonatomic,retain) IBOutlet UIImageView *imageView;
-(IBAction) click:(id) sender;
#end
and this is the implementation:
#import "TutorialViewController.h"
#implementation TutorialViewController
#synthesize labelText;
#synthesize imageView;
-(void) click:(id)sender {
imageView = [[UIImageView alloc]initWithImage:[UIImage imageNamed:#"1.png"]];
NSString *titleOfButton = [sender titleForState:UIControlStateNormal];
NSString *newText = [[NSString alloc]initWithFormat:#"%#",titleOfButton];
// Change Image When Clicking Color Button
if([titleOfButton isEqualToString:#"Blue"]){
NSLog(#"Blue");
UIImage *image = [UIImage imageNamed:#"1.png"];
imageView.image = image;
[image release];
}else{
UIImage *image = [UIImage imageNamed:#"2.png"];
imageView.image = image;
[image release];
NSLog(#"Else");
}
labelText.text = newText;
[newText release];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
}
#pragma mark - View lifecycle
- (void)viewDidUnload
{
[super viewDidUnload];
self.labelText = nil;
}
-(void) dealloc{
[labelText release];
[imageView release];
[super dealloc];
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
#end
When i start the app, it throws an Exception:
'NSInternalInconsistencyException', reason: '-[UIViewController _loadViewFromNibNamed:bundle:] loaded the "TutorialViewController" nib but the view outlet was not set.'
Can any one help me with my code ?
And additionally , could you please tell me about those bad written behaviors in my code.
Many many thanks !

Connect the root UIView inside your Xib to the File's Owner's view.

Open up your .xib file, then in Objects click on View, then click on Connections Inspector and from there Control + Click on the circle in Referencing Outlets and drag it to the File's Owner and from the pop-up menu select view .... :)
EDIT:
Your View is the Main UIVIEW, whatever you will put in it or under it in hierarchy will be shown automatically. As you have used UIImageView in it (You can see the hierarchy of views and objects in Objects, column left to xib under the PlaceHolders). When you connect the UIView(parent View) to File's Owner. It shows all other views which are included in the main view. So when you connected the main view with File's Owner it resolved your issue.

Well, the error message seems pretty clear:
loaded the "TutorialViewController" nib but the view outlet was not
set.'
Check the outlets on your TutorialViewController nib. Seems like the view outlet is not connected to anything. To fix it, connect your top-level-view to the outlet (control drag).

Related

UIPopOverScreen troubles

Recently I have taken interest in making a popover screen. In my Navigation bar I made this button and when I click on it it should make a popover screen appear.
So I started searching for a usefull tutorial and yet I found mostly tutorials made with interface builder, which is not what I want. So I started experimenting on my own.
This is my result:
First I set the necessary properties in the MainVC.h
Also mind the
#import <UIKit/UIKit.h>
#import "ThePopOverVC.h"
#interface PopoverPrototypeViewController : UIViewController <UIPopoverControllerDelegate>
{
ThePopOverVC *popover;
UIPopoverController *popoverController;
UIButton *popoverButton;
}
#property (nonatomic,retain) ThePopOverVC *popover;
#property (nonatomic,retain) UIPopoverController *popoverController;
#property (nonatomic,retain) UIButton *popoverButton;
- (void)popoverActivation;
#end
Then I set up my view in the MainVC.m
It prepares the view for the popoverscreen when pressing a button.
#import "PopoverPrototypeViewController.h"
#implementation PopoverPrototypeViewController
#synthesize popover;
#synthesize popoverController;
#synthesize popoverButton;
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Release any cached data, images, etc that aren't in use.
}
#pragma mark - View lifecycle
- (void)loadView
{
[super loadView];
self.view.backgroundColor = [UIColor blueColor];
popover = [[ThePopOverVC alloc] init];
popoverController = [[UIPopoverController alloc] initWithContentViewController:popover];
popoverController.popoverContentSize = CGSizeMake(300, 300);
popoverController.delegate = self;
self.popoverButton = [[UIButton alloc] initWithFrame:CGRectMake(100, 100, 400, 100)];
self.popoverButton.backgroundColor = [UIColor lightGrayColor];
[self.popoverButton setTitle:#"Click me!" forState:UIControlStateNormal];
[self.popoverButton addTarget:self action:#selector(popoverActivation) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:self.popoverButton];
}
- (void)popoverActivation
{
if ([self.popoverController isPopoverVisible]) {
[self.popoverController dismissPopoverAnimated:YES];
} else {
UIBarButtonItem *settingsBarButton = [[UIBarButtonItem alloc] initWithCustomView:self.popoverButton];
[self.popoverController presentPopoverFromBarButtonItem:settingsBarButton permittedArrowDirections:UIPopoverArrowDirectionUp animated:YES];
}
}
- (BOOL)popoverControllerShouldDismissPopover:(UIPopoverController *)popoverController
{
return YES;
}
- (void)popoverControllerDidDismissPopover:(UIPopoverController *)popoverController
{
NSLog(#"something");
}
Ok, the MainVC should be setup, now it's time to show the popoverContentViewController.
For my experiment I just want it to be an empty view with just a different backgroundColor.
So the popoverVC.h is empty:
#import <UIKit/UIKit.h>
#interface ThePopOverVC : UIViewController
#end
My popoverVC.m is equally empty except for the backgroundColor change:
#import "ThePopOverVC.h"
#implementation ThePopOverVC
- (void)loadView
{
[super loadView];
self.view.backgroundColor = [UIColor yellowColor];
}
You would say this shouldn't be too hard. But yet I'm experiencing problems loading the project.
I'm getting the following warning: warning: Unable to restore previously selected frame.
Well here comes the question:
What have I overlooked? What have I done wrong and how can I make this simple prototype work?
//---EDIT---//
OK, I'm a bloody idiot for overlooking this one.
[super loadView];
The super loadView wasn't called and gave me this simple problem.
I edited the code so it works properly now.
Use this as a tutorial on how to make UIPopOverScreens if you will (or whatever).
Ref: http://www.raywenderlich.com/1056/ipad-for-iphone-developers-101-uipopovercontroller-tutorial
[super loadView];
Was missing from ThePopOverVC.m
Pretty silly to overlook.. but yeah, it works now.

Objective-C Memory management: ViewController in a ViewController that's inside a UITabBarController

I have a UITabBarController with three ViewControllers (A, B, and C). In ViewControllerB I have a UIScrollView. The UIScrollView consists of several instances of my PhotoViewController. These PhotoViewController objects are called from ViewControllerA, not ViewController B, where they're located.
The PhotoViewController instances have a UIImage and a two buttons. And at first, when I clicked on a button in one of my PhotoViewController instances I received a 'Thread 1: Program received signal: "EXC_BAD_ACCESS"' error. Looking around on stackoverflow that error seems to appear whenever there are memory management issues.
Since I was creating the PhotoViewController objects in a loop from a method called in ViewControllerA, and releasing those objects, I figured that by the time I switched over to ViewControllerB they were already released - and hence the memory issue.
But that's just my guess. Could you tell me if I should just stop releasing the PhotoViewController objects inside of the loop code? Because that's what I did (just commented that line out) and the program "works" fine. However, I'm still not sure if this is the proper way to handle it and if it is causing unknown memory management issues.
Here is some of my code:
ViewControllerA.m
//Creating an album in ViewControllerB, the photos in the album are PhotoViewController objects
-(IBAction)showAlbum:(UIButton *)sender
{
//Go goes here to get an album and display it in the UIScrollView
albumID = #"ALBUM_ID";
NSString* graphUrl = [NSString stringWithFormat:#"%#/photos?limit=10", albumID];
[_facebook requestWithGraphPath:graphUrl andDelegate:self];
}
...
- (void)request:(FBRequest *)request didLoad:(id)result {
//Code for array of photos
NSLog(#"%#",result);
NSString *requestType = [request.url stringByReplacingOccurrencesOfString:#"https://graph.facebook.com/" withString:#""];
if ([requestType isEqualToString:[NSString stringWithFormat:#"%#/photos?limit=10", albumID]]){
NSArray *photoAlbumArray=(NSArray*)[result valueForKey:#"data"];
[self.label setText:[NSString stringWithFormat:#"%i", [photoAlbumArray count]]];
for(UIViewController *controller in self.tabBarController.viewControllers)
{
if([controller isKindOfClass:[ViewControllerB class]])
{
ViewControllerB *mtbvc = (ViewControllerB *)controller;
[mtbvc setArray:photoAlbumArray];
self.tabBarController.selectedIndex = 1;//switch over to the second view to see if it worked
}
}
}
...
#end
ViewControllerB.m
//loop where I create PhotoViewController objects
- (void) viewWillAppear:(BOOL)animated
{
[super viewWillAppear:YES];
arrayCount = [array count];
scroller.delegate=self;
scroller.pagingEnabled=YES;
scroller.directionalLockEnabled=YES;
scroller.showsHorizontalScrollIndicator=NO;
scroller.showsVerticalScrollIndicator=NO;
//should have an array of photo objects and the number of objects, correct?
scrollWidth = 0;
scroller.contentSize=CGSizeMake(arrayCount*scroller.frame.size.width, scroller.frame.size.height);
for (int i = 0; i < arrayCount;i++) {
PhotoViewController *pvc = [[PhotoViewController alloc] initWithNibName:#"PhotoViewController" bundle:nil];
UIImageView *scrollImageView = [[UIImageView alloc] initWithFrame:CGRectOffset(scroller.bounds, scrollWidth, 0)];
CGRect rect = scrollImageView.frame;
pvc.view.frame = rect;
[pvc view];
pvc.label.textColor = [UIColor whiteColor];
id individualPhoto = [array objectAtIndex:i];
NSLog(#"%#",individualPhoto);
NSArray *keys=[individualPhoto allKeys];
NSLog(#"%#",keys);
NSString *imageURL=[individualPhoto objectForKey:#"source"];
//here you can use this imageURL to get image-data and display it in imageView
NSURL *url = [NSURL URLWithString:imageURL];
NSData *data = [NSData dataWithContentsOfURL:url];
pvc.imageView.image = [[UIImage alloc] initWithData:data];
pvc.label.text = [individualPhoto objectForKey:#"id"];
//check to make sure the proper URL was passed
//I have an imageView next to the UIScrollView to test whether that works - it does.
[scroller addSubview:pvc.view];
[scrollImageView release];
//[pvc release];
scrollWidth += scroller.frame.size.width;
}
if (arrayCount > 3) {
pageControl.numberOfPages=3;
} else {
pageControl.numberOfPages=arrayCount;
}
pageControl.currentPage=0;
//[self.view addSubview:scroller];
}
PhotoViewController.m
#import "PhotoViewController.h"
#implementation PhotoViewController
#synthesize label, imageView;
-(IBAction)likeButton:(UIButton *)sender
{
//code goes here
for(UIViewController *controller in self.tabBarController.viewControllers)
{
if([controller isKindOfClass:[DemoAppViewController class]])
{
DemoAppViewController *davc = (DemoAppViewController *)controller;
[davc likePicture:self.label.text];
}
}
self.tabBarController.selectedIndex = 0;//switch over to the third view to see if it worked
}
-(IBAction)skipButton:(UIButton *)sender
{
//code goes here
}
-(IBAction)likeCommentButton:(UIButton *)sender
{
//code goes here
}
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)dealloc
{
[super dealloc];
}
- (void)didReceiveMemoryWarning
{
// Releases the view if it doesn't have a superview.
[super didReceiveMemoryWarning];
// Release any cached data, images, etc that aren't in use.
}
#pragma mark - View lifecycle
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
}
- (void)viewDidUnload
{
[super viewDidUnload];
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
// Return YES for supported orientations
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
#end
PhotoViewController.h
#import <UIKit/UIKit.h>
#import "DemoAppViewController.h"
#import "MyTabBarViewController.h"
#interface PhotoViewController : UIViewController {
IBOutlet UILabel *label;
IBOutlet UIImageView *imageView;
UIButton *likeButton;
UIButton *skipButton;
UIButton *likeCommentButton;
}
#property (nonatomic, retain) UILabel *label;
#property (nonatomic, retain) UIImageView *imageView;
-(IBAction)likeButton:(UIButton *)sender;
-(IBAction)skipButton:(UIButton *)sender;
-(IBAction)likeCommentButton:(UIButton *)sender;
#end
To write iOS apps, it is critical that you understand the memory management rules.
In ViewControllerB, viewDidLoad, you alloc the pvc.
Further down, you add the pvc's view as a subview of the scroller. This retains the pvc's view, but not the pvc itself. Then when you release the pvc, it's retain count is zero, and when you reference it later, it's gone. Crash. It seems like you need to pass in and retain a reference to the pvc in the controller that's using it.
I am not sure why you are using PhotoViewController(Subclassing UIViewController) instead of PhotoView(subclassing UIView). As you are not using any of the facility of the viewcontroller(no life cycle method and other).
If you subclass PhotoViewController with UIView and remove the viewcontroller's methods it will work and will not cause any memory issues as you have aleready discussed in your discussion with Rayfleck. ( it will be retained by parent view controller.)
If you are thinking about the events, then these will also be handled by view itself. But if you want to handle it in your controller then you can easily delegate, or pass your controller reference and invoke the event on it.
Thanks,

Adding an overlay to a grid tableView

I have a tableview which each row has 4 images. I have implemented a share option which will allow the user to select multiple images. How can I add an overlay or some kind of visual effect to show that the image is selected?
I would like to add some overlay to display that an image is selected, but How would this be done without adding a new set of subview for each thumbnail? And once that is done, how would the selection of the new views be linked back to the images behind them so that they can be added to an array?
Or is there an easier way to do this?
Thanks
Depending on how you're implementing this grid view, it might make sense to track all of the selecting and deselecting at that level.
As for the overlay, the quick and dirty way is to subclass UIImageView, add a BOOL property called selected. Then you can override the setter for selected and handle showing or hiding your overlay view.
Here's how I would setup my subclass. First the interface:
#interface SelectableImageView : UIImageView
#property (nonatomic, assign, getter = isSelected) BOOL selected;
#end
and the implementation...
#interface SelectableImageView ()
#property (nonatomic, retain) UIView *overlayView;
#end
#implementation SelectableImageView
#synthesize selected;
#synthesize overlayView;
- (id)initWithFrame:(CGRect)frame
{
if (self = [super initWithFrame:frame])
{
overlayView = [[UIView alloc] initWithFrame:frame];
overlayView.backgroundColor = [UIColor colorWithWhite:0.0 alpha:0.75];
overlayView.hidden = YES;
[self addSubview:overlayView];
}
return self;
}
- (void)setSelected:(BOOL)flag
{
selected = flag;
self.overlayView.hidden = !flag;
}
- (void)dealloc
{
[overlayView release], self.overlayView = nil;
[super dealloc];
}
#end

iphone app with multiple views/subviews: memory is not being deallocated

I have an iPhone application that loads succesive views in a framework based on the one explained in this link (basically a main ViewController that loads/removes additional views with a displayView method). In my application I am using NIBs (the example link uses coded views) though so each of my ViewControllers has its accompanying nib.
Debugging in Instruments shows no leaks but if I enter/leave a section (ViewController with its View.xib), the nib remains in memory so after a few in/outs memory starts to accumulate.
I know the nib is not being unloaded because one is almost programmatically created (no stuff in IB) while another does have images and buttons created in IB. The large one is loaded first and the small one loads next. You would expect a reduction in allocation in Instruments.
How can I prevent this?
My structure is as follows, with a few comments below:
`MyAppDelegate.h`
#import <UIKit/UIKit.h>
#class RootViewController;
#interface MyAppDelegate : NSObject <UIApplicationDelegate> {
UIWindow *window;
RootViewController *viewController;
}
#property (nonatomic, retain) IBOutlet UIWindow *window;
#property (nonatomic, retain) IBOutlet RootViewController *viewController;
-(void) displayView:(int)intNewView;
#end
`MyAppDelegate.m`
#import "MyAppDelegate.h"
#import "RootViewController.h"
#implementation MyAppDelegate
#synthesize window;
#synthesize viewController;
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
[window addSubview:viewController.view];
[window makeKeyAndVisible];
return YES;
}
- (void)applicationDidReceiveMemoryWarning:(UIApplication *)application {
}
-(void) displayView:(int)intNewView {
[viewController displayView:intNewView];
}
- (void)dealloc {
[viewController release];
[window release];
[super dealloc];
}
#end
This controller handles subview load/removes:
`RootViewController.h`
#import <UIKit/UIKit.h>
#interface RootViewController : UIViewController {
}
- (void) displayView:(int)intNewView;
#end
`RootViewController.m`
#import "RootViewController.h"
#import "ViewController.h"
#implementation RootViewController
UIViewController *currentView;
- (void) displayView:(int)intNewView {
NSLog(#"%i", intNewView);
[currentView.view removeFromSuperview];
[currentView release];
switch (intNewView) {
case 1:
currentView = [[ViewController alloc] initWithNibName:#"View" bundle:nil];
break;
}
[self.view addSubview:currentView.view];
}
- (void)viewDidLoad {
currentView = [[ViewController alloc]
initWithNibName:#"View" bundle:nil];
[self.view addSubview:currentView.view];
[super viewDidLoad];
}
- (void)dealloc {
[currentView release];
[super dealloc];
}
#end
There would be as many case as "detail" ViewControllers I have (right now I have 3 case but this will grow to 10 or more). The purpose of this structure is to easily move from one "section" of the application to another (NavBar controller or TabBar controller do not suit my specific needs).
`ViewController.h`
// Generic View Controller Example
#import <UIKit/UIKit.h>
#interface ViewController : UIViewController {
UIImageView *_image1;
UIImageView *_image2;
NSTimer *_theTimer;
}
#property (nonatomic, retain) IBOutlet UIImageView *image1;
#property (nonatomic, retain) IBOutlet UIImageView *image2;
#property (nonatomic, retain) NSTimer *theTimer;
#end
`ViewController.m`
#import "ViewController.h"
#import "MyAppDelegate.h"
#synthesize image1 = _image1, image2 = _image2, theTimer = _theTimer;
- (void)loadMenu {
[self.theTimer invalidate];
self.theTimer = nil;
MyAppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
[appDelegate displayView:2];
}
-(void)setView:(UIView*)aView {
if (!aView){
self.image1 = nil;
self.image2 = nil;
}
[super setView:aView];
}
- (void)viewDidLoad {
//some code
[super viewDidLoad];
}
- (void)viewDidUnload {
self.image1 = nil;
self.image2 = nil;
}
- (void)dealloc {
NSLog(#"dealloc called");
[self.theTimer invalidate];
[self.theTimer release];
[self.image1 release];
[self.image2 release];
[super dealloc];
}
Notice the NSLog in dealloc. This is being called (I can see it in the console) but the memory needed for the nib is not freed (Instruments shows an increase in memory allocation when leaving a section, because a new nib is loaded).
Any help will be greatly appreciated. I have tried a million different things and I cannot get the nibs to unload.
After a million different tries I finally ran into this forum.
It states:
Apparently images assigned in IB are loaded into image views using imageNamed. imageNamed caches the images in a way that makes them unloadable. You could load the images in viewDidLoad with initWithContentsOfFile and then assign them to the views.
Somewhere else I had read that imageNamed is the devil so I'd rather not have my images load that way.
(BTW this is iPhone OS 3.1 I'm using)
What I ended up is leaving the UIImageView intact in IB but with an empty .image value. The modified code is something like:
- (void)viewDidLoad {
NSString *path = [NSString stringWithFormat:#"%#/%#", [[NSBundle mainBundle] resourcePath], #"myImageThatBeforeWasAValueinIB.jpg"];
UIImage *image = [UIImage imageWithContentsOfFile:path];
outlet.image = image;
// do the rest of my stuff as it was
[super viewDidLoad];
}
- (void)dealloc {
outlet.image = nil;
[outlet release], outlet = nil;
[super dealloc];
}
And now everything works like a charm! Memory is recovered when I unload a nib and when I get memory warnings.
So pretty much if you have IBOutlets for UIImageViews and memory is a concern (it always is I guess), you can design all you want in IB and when the time comes to connect them to outlets, remove the image reference in IB and create it from code. IB is really good for laying out your app. It would suck to have to do all that thing by code, but I also found this nice utility that converts nibs to objective c code although I haven't tested it yet.
Did you try setting your outlet variables to nil in dealloc?
You are correctly implementing the setView method, but you are setting your outlet variables to nil in the viewDidUnload method instead of dealloc. As discussed here, you should implement dealloc as follows:
- (void)setView:(UIView *)aView {
if (!aView) { // view is being set to nil
// set outlets to nil, e.g.
self.anOutlet = nil;
}
// Invoke super's implementation last
[super setView:aView];
}
- (void)dealloc {
// release outlets and set outlet variables to nil
[anOutlet release], anOutlet = nil;
[super dealloc];
}
EDIT: if the outlets are UIImageViews, then it may be the case that you need to do
anOutlet.image = nil;
because setting the UIImage’s instance image property should increase the retain count of the UIImage’s instance by 1.

iPhone - creating a loading view

When the app is in one view controller, I want to add a view to simulate that data is being loaded when I click my tab bar controller to open another view controller.
Example: When I the app is in the recorder-view, I want it to show a loading view (a view with a activity indicator) when I change to the list of recorded files (which can take some time to load). I've tried manipulate this with the viewWillDisappear-event, but I can't get it to work - the view is not being added before after the viewDidAppear-event occurs.
Anyone have any thoughts regarding this?
Thanks
Thank you for your reply. I tried doing like tou suggested, but I still can't get it to show when I want. I try to set hidden = NO in my viewWillDisappear-event, but it does not show before that view controller disappears and the next one appears
Right now it sounds like you have a UITabBarController That takes up the whole screen. What I would do is put the loading view above the TabBarController and hide it when not necessary. I would create a subclass of loadingViewController in the same xib your tab bar controller came from (or programatically if you desire) and set it to an IBOutlet of the App Delegate.
Something like this:
//In your App Delegate
- (void)applicationDidFinishLaunching:(UIApplication *)application {
[window addSubview:tabBarController.view];
loadingView.hidden = YES;
[window insertSubview:loadingViewController.view aboveSubview:abBarController.view];
[window makeKeyAndVisible];
}
//In your loading View Controller
- (void) setLoadingViewHidden:(BOOL)hidden {
self.view.hidden = hidden;
self.activityIndicator.animating = hidden;
}
The way I've done this in the past is to have a content view which houses either an activity view or the view proper.
In the view controller's nib, instead of adding subviews to the main view, leave it empty and create a new view (such as a table view in the example below) for the view proper.
Also create an activity view (with a threaded progress indicator or somesuch) and a "no results" view.
Then derive your controller class from the something like the following:
//
// ContainerViewController.h
//
#import <UIKit/UIKit.h>
#interface ContainerViewController : UIViewController
{
UIView *myContainerView;
UITableView *myTableView;
UIView *mySearchActivityView;
UIView *myZeroResultsView;
UIView *myCurrentlyShowingView;
}
#property (retain, nonatomic) IBOutlet UIView *containerView;
#property (retain, nonatomic) IBOutlet UITableView *tableView;
#property (retain, nonatomic) IBOutlet UIView *searchActivityView;
#property (retain, nonatomic) IBOutlet UIView *zeroResultsView;
#property (assign) UIView *currentlyShowingView;
#end
//
// ContainerViewController.m
//
#import "ContainerViewController.h"
#implementation ContainerViewController
#synthesize containerView = myContainerView;
#synthesize tableView = myTableView;
#synthesize searchActivityView = mySearchActivityView;
#synthesize zeroResultsView = myZeroResultsView;
- (void)dealloc
{
[myContainerView release], myContainerView = nil;
[myTableView release], myTableView = nil;
[mySearchActivityView release], mySearchActivityView = nil;
[myZeroResultsView release], myZeroResultsView = nil;
myCurrentlyShowingView = nil;
[super dealloc];
}
- (void)viewDidLoad
{
[super viewDidLoad];
self.currentlyShowingView = mySearchActivityView;
mySearchActivityView.backgroundColor = [UIColor clearColor];
myZeroResultsView.backgroundColor = [UIColor clearColor];
}
- (void)setCurrentlyShowingView:(UIView *)view
{
[myCurrentlyShowingView removeFromSuperview];
CGRect frame = view.frame;
frame.size = myContainerView.frame.size;
view.frame = frame;
[myContainerView addSubview:view];
myCurrentlyShowingView = view;
if (view == myTableView)
[myTableView reloadData];
}
- (UIView *)currentlyShowingView
{
return myCurrentlyShowingView;
}
#end
And in the -viewDidLoad method of the derived class, set off the (asynchronous) query:
- (void)viewDidLoad
{
[super viewDidLoad];
myQueryLoader = [[QueryLoader alloc] initWithQuery:#"whatever" delegate:self];
self.currentlyShowingView = mySearchActivityView;
}
and in the delegate callback:
- (void)queryLoader:(QueryLoader *)queryLoader didEndWithResults:(id)results error:(NSError *)error
{
myItems = [results retain];
if (myItems)
self.currentlyShowingView = myTableView;
else
self.currentlyShowingView = myZeroResultsView;
}
Hope this helps!