4

In the page control sample from apple there is a ScrollView in the interface builder. It is linked with the corresponding IBOutlet. I want to change the code so this is all done programatically. I delete the interface builder object, I delete the IBOutlet keyword. I alloc and init the scrollView, but nothing appears when I run the program.

I assume this is because I need to assign it as a subView to the main view. Or do I? I still don't really understand how all the views work and interact with each other. If I do [self.view addSubView:ScrollView]; I get a runtime error (or something, it usually just says something like BAD ACCESS or SIGABRT).

What am I doing wrong? Am I on the wrong path completely? (only two days in to ios programming, still a bit lost in the woods)

awakeFromNib in phone content controller:

- (void)awakeFromNib
{
scrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height)];

// load our data from a plist file inside our app bundle
NSString *path = [[NSBundle mainBundle] pathForResource:@"content_iPhone" ofType:@"plist"];
self.contentList = [NSArray arrayWithContentsOfFile:path];

// view controllers are created lazily
// in the meantime, load the array with placeholders which will be replaced on demand
NSMutableArray *controllers = [[NSMutableArray alloc] init];
for (unsigned i = 0; i < kNumberOfPages; i++)
{
    [controllers addObject:[NSNull null]];
}
self.viewControllers = controllers;
[controllers release];

// a page is the width of the scroll view
scrollView.pagingEnabled = YES;
scrollView.contentSize = CGSizeMake(scrollView.frame.size.width * kNumberOfPages,  scrollView.frame.size.height);
scrollView.showsHorizontalScrollIndicator = NO;
scrollView.showsVerticalScrollIndicator = NO;
scrollView.scrollsToTop = NO;
scrollView.delegate = self;

pageControl.numberOfPages = kNumberOfPages;
pageControl.currentPage = 0;

// pages are created on demand
// load the visible page
// load the page on either side to avoid flashes when the user starts scrolling
//
[self loadScrollViewWithPage:0];
[self loadScrollViewWithPage:1];
}

header file:

#import <UIKit/UIKit.h>
#import <Foundation/Foundation.h>

#import "ContentController.h"

@interface PhoneContentController : ContentController <UIScrollViewDelegate>
{   
UIScrollView *scrollView;
UIPageControl *pageControl;
NSMutableArray *viewControllers;

// To be used when scrolls originate from the UIPageControl
BOOL pageControlUsed;
}

@property (nonatomic, retain) UIScrollView *scrollView;
@property (nonatomic, retain) IBOutlet UIPageControl *pageControl;

@property (nonatomic, retain) NSMutableArray *viewControllers;

- (IBAction)changePage:(id)sender;

@end

appDelegate:

#import "AppDelegate.h"
#import "ContentController.h"

@implementation AppDelegate

@synthesize window, contentController;

- (void)dealloc
{
[window release];
[contentController release];

[super dealloc];
}

- (void)applicationDidFinishLaunching:(UIApplication *)application
{
NSString *nibTitle = @"PadContent";
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone)
{
    nibTitle = @"PhoneContent";
}
[[NSBundle mainBundle] loadNibNamed:nibTitle owner:self options:nil];

[self.window addSubview:self.contentController.view];
[window makeKeyAndVisible];
}

@end

and the scrollView has been deleted from the xib file. Note: this is a new version of the downloaded program where all I have changed is deleting the IBOutlet keyword for the scrollView, deleted the scroll from the xib and added the alloc, init line in awake from nib.

I've had suggestions to change the appDelegate and change the awakeFromNib to an init method, i've tried all this but it still doesn't work.

Dollarslice
  • 9,917
  • 22
  • 59
  • 87
  • 1
    Yes, you are on the wrong path unless you have some very specific reason to not use Interface Builder. – zaph Jan 18 '12 at 11:37
  • I didn't mean the wrong path in that sense, I just meant the wrong path to figure out my problem. And yes I do have a specific reason. – Dollarslice Jan 18 '12 at 11:38
  • above the scrollView.etc here I have done alloc and init https://developer.apple.com/library/ios/#samplecode/PageControl/Listings/Classes_iPhone_PhoneContentController_m.html#//apple_ref/doc/uid/DTS40007795-Classes_iPhone_PhoneContentController_m-DontLinkElementID_20 – Dollarslice Jan 18 '12 at 11:41
  • and here I have removed the IBOutlet of the corresponding property for scrollView https://developer.apple.com/library/ios/#samplecode/PageControl/Listings/Classes_iPhone_PhoneContentController_h.html#//apple_ref/doc/uid/DTS40007795-Classes_iPhone_PhoneContentController_h-DontLinkElementID_19 – Dollarslice Jan 18 '12 at 11:42
  • and I have also deleted the ScrollView from the Interface builder which was over a window. I assume I have to tell the program it should be a subview to the window? but my attempts have failed. – Dollarslice Jan 18 '12 at 11:43
  • 1
    @SirYakalot Please post your code. It's cumbersome for us to try and puzzle it together ourselves. Your problem is probably easily fixed then. – fzwo Jan 18 '12 at 11:47
  • 3
    @CocoaFu Creating the view hierarchy in code instead of IB is not a bad idea at all. Please don't go around spreading FUD. Some of the best developers out there prefer not to use IB. I find it much easier to really know what I'm doing when I'm laying out stuff in code. – fzwo Jan 18 '12 at 11:49
  • but the amount of code would be huge and I've provided links to it. fine.. – Dollarslice Jan 18 '12 at 13:31

3 Answers3

2

Since you're not loading the interface from a nib file, you should set up your UIScrollView in your PhoneContentController's init method:

- (id)init
{
    [super init];

    if (self) {
        scrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(0, 20, 320, 440)];
        pageControl = [[UIPageControl alloc] initWithFrame:CGRectMake(<#CGFloat x#>, <#CGFloat y#>, <#CGFloat width#>, <#CGFloat height#>)]; // Place it where you want it.
        viewControllers = [[NSMutableArray alloc] init];

        // load our data from a plist file inside our app bundle
        NSString *path = [[NSBundle mainBundle] pathForResource:@"content_iPhone" ofType:@"plist"];
        self.contentList = [NSArray arrayWithContentsOfFile:path];

        // view controllers are created lazily
        // in the meantime, load the array with placeholders which will be replaced on demand
        NSMutableArray *controllers = [[NSMutableArray alloc] init];
        for (unsigned i = 0; i < kNumberOfPages; i++)
        {
            [controllers addObject:[NSNull null]];
        }
        self.viewControllers = controllers;
        [controllers release];

        // a page is the width of the scroll view
        scrollView.pagingEnabled = YES;
        scrollView.contentSize = CGSizeMake(scrollView.frame.size.width * kNumberOfPages, scrollView.frame.size.height);
        scrollView.showsHorizontalScrollIndicator = NO;
        scrollView.showsVerticalScrollIndicator = NO;
        scrollView.scrollsToTop = NO;
        scrollView.delegate = self;

        pageControl.numberOfPages = kNumberOfPages;
        pageControl.currentPage = 0;

        // pages are created on demand
        // load the visible page
        // load the page on either side to avoid flashes when the user starts scrolling
        //
        [self loadScrollViewWithPage:0];
        [self loadScrollViewWithPage:1];
    }

    return self;
}

In your AppDelegate, make the following changes:

- (void)applicationDidFinishLaunching:(UIApplication *)application
{
    self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];

    if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone) {
        contentController = [[PhoneContentController alloc] init];
    } else {
        contentController = [[PadContentController alloc] init];
    }

    [self.window addSubview:contentController.view];
    [window makeKeyAndVisible];
}
Iñigo Beitia
  • 6,303
  • 4
  • 40
  • 46
  • It doesn't break but it doesn't display what it did before I removed the nib stuff. Just a blank screen now. Also my init method is called awakeFromNib. Is that significant? – Dollarslice Jan 18 '12 at 12:11
  • oh no sorry, my bad. It does break. I get EXC_BAD_ACCESS on the add subview line – Dollarslice Jan 18 '12 at 12:13
  • @SirYakalot, I've made changes to the answer, make sure you remove the `addSubview` line from the init method. I would recommend using `init`instead of `awakeFromNib`. – Iñigo Beitia Jan 18 '12 at 12:25
  • I can just change the name and the program will still work? why is this? – Dollarslice Jan 18 '12 at 12:29
  • still doesn't work for me. I get a non-scrollable black screen. the content is gone. – Dollarslice Jan 18 '12 at 12:36
  • Since you're not loading from nib anymore from the `AppDelegate`'s `applicationDidFinishLaunching:`, the method `awakeFromNib` won't be called. Instead notice how you call `init` on the new `PhoneContentController` instance. – Iñigo Beitia Jan 18 '12 at 12:38
  • It says that Phone and Pad content controller are unknown receivers. It suggests that I meant content controller? – Dollarslice Jan 18 '12 at 12:43
  • seems there is an extra bracket in your code before alloc. plus you need to include the appropriate headers. After that's done you run it and it breaks. EXC_BAD_ACCESS – Dollarslice Jan 18 '12 at 12:53
  • There's no extra bracket before alloc: the first `[` corresponds to the `]` after `init`. It's typical Obj-C style to combine calls to alloc and init: `[[alloc Foo] init];` That means allocate an instance of Foo, and then initialize the new object. You should always follow this pattern when creating objects. – Caleb Jan 18 '12 at 13:04
  • Sorry for the typo. I've updated the answer and tested it, it now works. – Iñigo Beitia Jan 18 '12 at 13:15
  • Thank you! That worked. Sorry for needing so much help with this. would you mind very briefly explaining why you made the changes you did and what they do? I understand if you don't have time / can't be bothered. Thanks again! – Dollarslice Jan 18 '12 at 13:53
  • When you use Outlets in InterfaceBuilder, the initializations are done for you, that's why I needed to add init calls for the scrollView, the page controller and the array holding the pages. Since you no longer load from nib, the awakeFromNib method is never called, so you need to put all the setup code of the view in the Class' init. – Iñigo Beitia Jan 18 '12 at 14:23
0

Simple Method: You can created multiple times if you need means

- (void)viewDidLoad
{
    [super viewDidLoad];

    int x = 0;
    int y = 10;
    for(int i=0; i<5; i++)
    {
        UIScrollView *scrollview=[[UIScrollView alloc]initWithFrame:CGRectMake(x, y, 50, 50)];
        scrollview.showsVerticalScrollIndicator=YES;
        scrollview.scrollEnabled=YES;
        scrollview.userInteractionEnabled=YES;
        scrollview.backgroundColor = [UIColor greenColor];
        [self.view addSubview:scrollview];
        //scrollview.contentSize = CGSizeMake(50,50);
        x=x+55;

        //[self myscrollView];
    }
}
Rajesh Loganathan
  • 11,129
  • 4
  • 78
  • 90
0

you simply put this inside awakeFromNib method

scrollView=[[UIScrollView alloc] initWithFrame:CGRectMake(0, 20, 320, 440)];

no need to add as subview because in phoneContentController xib there are no views inside that.so how can you add like[ self.view addSubView:ScrollView];this is because phoneContentController is not type of UIViewController Class. it's a sub Class of ContentController which is subClass of NSObject inside that project.

beryllium
  • 29,669
  • 15
  • 106
  • 125
Mudit Bajpai
  • 3,010
  • 19
  • 34
  • thank you, I'm not sure I fully understand the view hierarchy still. Also it still doesn't work. It doesn't break but nothing is displayed. – Dollarslice Jan 18 '12 at 12:15
  • I changed the background colour to red, and the screen is red so I guess it is displaying, but the things that used to draw on it aren't there anymore and it doesn't seem to be scrolling... there must be some link somewhere that is missing.. – Dollarslice Jan 18 '12 at 12:17
  • i have done the same thing and it's working correct.it mean's you have change some other code also. – Mudit Bajpai Jan 18 '12 at 12:20
  • the only other thing I changed is the UILabel called numberTitle inside of MyViewController. I did the same thing - removing it from the xib file and coding it in programatically. It worked before I changed the scrollView. In LoadScrollViewWithPage, at the end of the second if statement I am doing ` [controller.view addSubview:controller.numberTitle];` It is also now a UITextView, not a UILabel – Dollarslice Jan 18 '12 at 12:26
  • I suppose what i'm asking is how can I then change numberTitle to ALSO be done programatically? – Dollarslice Jan 18 '12 at 12:32
  • actually I just re-downloaded the code, deleted the scrollView in xib, deleted the IBOutlet keyword and added the alloc init and it doesn't work. – Dollarslice Jan 18 '12 at 12:36
  • @SirYakalot: so you have add the scrollview and now you want to add UItextView in the scrollview? – Hiren Jan 18 '12 at 12:39
  • @SirYakalot:are You saying you are using initWithFrame and it's not working?....How can it's possible bcoz same thing i have done and it's working fine. – Mudit Bajpai Jan 18 '12 at 12:44
  • have you still got the scrollView inside your xib file? – Dollarslice Jan 18 '12 at 12:45
  • no, inside xib there are no scrollView.... i am only using alloc initwithframe inside awakeFromNib method nothing else – Mudit Bajpai Jan 18 '12 at 12:51
  • well If I make those three simple changes. Deleting the IBOutlet keyword from the property line of phonecontentcontroller, deleting the scroll view from the nib file and adding the alloc init at the top of awakeFromNib - the code runs but nothing displays but a blank white screen. – Dollarslice Jan 18 '12 at 12:55
  • yes i agree with this answer because you are using alloc init only, use alloc initwithframe . – Mudit Bajpai Jan 18 '12 at 13:01