2

So I have a UIViewController subclass called MyTabBarViewController that has a UIScrollView. Inside of MyTabBarViewController I'm creating an instance of another UIViewController subclass called PhotoViewController. (Note: I'm doing this so I can set up the IBOutlets using IB)

I'm trying to set the label of each PhotoViewController instance from my TabBarViewController. And I init with nib for each PhotoViewController so I was under the impression that each PhotoViewController instance would be wired up to their respective IBOutlets - allowing me to simply set the label name using pvc.label.text = @"text I want".

Could you explain why my logic is incorrect? Because it's not working and not really sure what to do. :-/

MyTabBarViewController.m

#import "MyTabBarViewController.h"


@implementation MyTabBarViewController
@synthesize pageControl,scroller;

-(IBAction)clickPageControl:(id)sender
{
    int page=pageControl.currentPage;
    CGRect frame=scroller.frame;
    frame.origin.x = frame.size.width * page;
    frame.origin.y = 0;
    [scroller scrollRectToVisible:frame animated:YES];
}

-(void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
{
    int page = scrollView.contentOffset.x/scrollView.frame.size.width;
    pageControl.currentPage=page;
}

- (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];
    scroller.delegate=self;
    scroller.pagingEnabled=YES;
    scroller.directionalLockEnabled=YES;
    scroller.showsHorizontalScrollIndicator=NO;
    scroller.showsVerticalScrollIndicator=NO;
    scroller.contentSize=CGSizeMake(pageControl.numberOfPages*scroller.frame.size.width, scroller.frame.size.height);
    CGFloat scrollWidth = 0;
    int pageNumber = 0;
    for (int i=0; i<3; i++)
    {
        PhotoViewController *pvc = [[PhotoViewController alloc] initWithNibName:@"PhotoViewController" bundle:nil];
        CGRect rect = scroller.frame;
        rect.size.height = scroller.frame.size.height;
        rect.size.width = scroller.frame.size.width;
        rect.origin.x = scroller.frame.origin.x + scrollWidth;
        rect.origin.y = scroller.frame.origin.y;
        pvc.label.text = [NSString stringWithFormat:@"%d", pageNumber];
        pvc.label.textColor = [UIColor redColor];
        pvc.view.frame  = rect;
        [scroller addSubview:pvc.view];
        [pvc release];
        pageNumber++;
        scrollWidth += scroller.frame.size.width;
    }
    pageControl.numberOfPages=3;
    pageControl.currentPage=0;
    [self.view addSubview:scroller];
}

- (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 is pretty straight-forward. And PhotoViewController.m is too but I've included the implementation file in the event that my problem is in there.

PhotoViewController.m

#import "PhotoViewController.h"


@implementation PhotoViewController
@synthesize label, imageView, sendButton, cancelButton;

- (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
NateHill
  • 345
  • 2
  • 7
  • 22

2 Answers2

2

You cant set any view related values like this(making object and set other enteries from that view).

Because you can't set any level's value before viewDidLoad of any view controller.What you need, you need set properties of string type for labels accordingly and set their values in MyTabBarViewController then from the stack pick up the object of the MyTabBarViewController class in PhotoViewController and then access it's properties and set your labels.

For picking the view object from stack you need to use this line

MyTabBarViewController *obj = (MyTabBarViewController *)[self.navigationController.viewControllers objectAtIndex: [self.navigationController.viewControllers count]-2];
Ishu
  • 12,797
  • 5
  • 35
  • 51
  • Thanks Ishu :-) I got the first part of your answer about `viewDidLoad` but I'm still a bit unclear about the second part of your answer. How would I set the values in MyTabBarViewController? And why would I need to set the values in MyTabBarViewController if later on I'm suppose to access PhotoViewController's properties and set the labels? I only ask because it sounds like a wasted step when I set the values in MyTabBarViewController if I'm later setting them in PhotoViewController. Thanks so much for the initial feedback though Isha! :-) – NateHill Jun 27 '11 at 04:42
  • In case if you make properties in MyTabBarViewController then the second part of answer helps. if you make property in photoViewController then you don't need. and i suppose the properties of MyTabBarViewController class in my answer. – Ishu Jun 27 '11 at 04:55
  • The most robust approach is to set independent properties in each PhotoViewController, to be referenced from viewDidLoad. (If you can use common values from the parent class, just set a parent property in the child object and use that to reference the parent.) This covers the minuscule chance that the phone will unload the view controller at some point due to low memory. But if you care to ignore that minuscule possibility, just reference "view" in the child before setting the labels. – Hot Licks Jun 27 '11 at 11:25
  • yeah, thats very true. need to make property in PhotoViewController not in MyTabBarViewController. – Ishu Jun 27 '11 at 11:29
  • @Daniel and @Ishu thank you so much for breaking this down for me. I went to the UIVIewController page on developer.apple to make sure that I understood you two correctly. View property mentioned: _If you access this property and its value is currently nil, the view controller automatically calls the loadView method and returns the resulting view. The default loadView method attempts to load the view from the nib file associated with the view controller (if any)._ -- I believe that's what you were telling me, correct? I added `[pvc view]` before setting my properties and everything worked. :-) – NateHill Jun 27 '11 at 14:38
  • @Daniel I'm still a bit unclear about the "more robust" approach you mentioned. Are you saying I should override my viewDidLoad method in PhotoViewController? And by parent class I take it that you referring to UIViewController, is this correct? As it stands it sounds like I should override the viewDidLoad method and send it a message from the MyTabBarController (i.e., `[pvc viewDidLoad]`) – NateHill Jun 27 '11 at 14:45
  • By "parent" I mean the MyTabBarController. Either store the parms in MyTabBarController and reference via a "parent" pointer that is a property set in PhotoViewController, or store the parms in PhotoViewController as independent properties. (But very few people worry about the out-of-memory scenario.) – Hot Licks Jun 28 '11 at 05:25
1

The IBOutlet entities don't exist until viewDidLoad, and that doesn't generally happen until you initiate a show. Therefore, in MyTabBarViewController you're addressing a label, et al, that doesn't exist. (Of course, Objective-C conveniently ignores calls on nil pointers, so it SEEMS like it all works -- just nothing happens.)

According to the spec, you can trigger loading by referring to the view property of the view controller, but I've never tried it.

Hot Licks
  • 47,103
  • 17
  • 93
  • 151