16

A little background: I'm going through the CS193P iTune videos and I was stuck on the assignment 3 for the longest time. Basically, the assignment asks you to programmatically create a custom view to display a shape on the screen. I'm not using any view controllers by the way.

I could not get my view to display until I finally dragged a View object in Interface Builder and change the object name to my custom view class. So my question is when people say to programmatically create a view, are they just saying manually create the class but when you need to display it use IB? I can't help feeling like I misunderstood something?

edit: let me be more clear. My custom view has been initialized with a frame of 0, 0, 200, 150 and drawRect is overriden to draw a square in it. My view doesn't even show up if try adding it to the main window within my controller:

    UIWindow* window = [UIApplication sharedApplication].keyWindow;
[window addSubview:polygonView];

However, if use drag a view in IB and change the class to my view class, it shows up fine.

Edit: Added some code. This is my controller's awakeFromNib method where the view should be drawn.

    - (void)awakeFromNib {
    shape = [[PolygonShape alloc] initWithNumberOfSides:numberOfSidesLable.text.integerValue minimumNumberOfSides:3 maximumNumberOfSides:12];
    polygonView = [[PolygonView alloc] initWithFrame:CGRectMake(0, 0, 320, 480)];
    UIWindow *window = [UIApplication sharedApplication].keyWindow;
    polygonView.backgroundColor = [UIColor blackColor];
    [window addSubview:polygonView];
    [self updateInterface];  
}

Part of my controller's updateInterface method:

- (void)updateInterface {
    [polygonView setPolygon:shape];
    [polygonView setNeedsDisplay];
...
}

PolygonView.h

#import <UIKit/UIKit.h>
#import "PolygonShape.h"

@interface PolygonView : UIView {
    IBOutlet PolygonShape *polygon; 
}

@property (readwrite, assign) PolygonShape *polygon;

- (void)drawRect:(CGRect)rect;
@end

PolygonView.m

#import "PolygonView.h"

@implementation PolygonView
@synthesize polygon;

- (id)initWithFrame:(CGRect)frame {

    self = [super initWithFrame:frame];
    if (self) {
        nslog(@"initialized");
    }
    return self;
}

- (void)drawRect:(CGRect)rect {
       CGRect bounds = [self bounds];

    [[UIColor grayColor] set];
    UIRectFill(bounds);

    CGRect square = CGRectMake(10, 10, 10, 100);
    [[UIColor blackColor] set];
    UIRectFill(square);

    [[UIColor redColor] set];
    UIRectFill(square);
    NSLog(@"drawRect called");
}
@end

The polygonView is being initialized but the drawRect isn't being called.

subject_x
  • 421
  • 1
  • 6
  • 15
  • Where is the keyWindow being created? If you're not loading a nib file (it's not clear from your question whether you are or not), then you would have to create the window first before adding your subview. – jlehr Jan 27 '11 at 22:24
  • It's being created in the AppDelegate class. Does this mean I have to #import my polygonView class there and create it there? – subject_x Jan 28 '11 at 05:13
  • Interestingly if I put the initialization and adding of my view to the window in my updateInterface method, it works but only after I click a button that calls the method. It seems like the code isn't being processes in awakeFromNib. Any ideas? – subject_x Jan 28 '11 at 18:44
  • Can someone who has been through the course be kind enough to share their code for the controller? This assignment is not for the actual class; I'm just trying to learn Obj-C on my own. At this point, I understand most of what's going on but there is obviously something I'm missing here. – subject_x Jan 31 '11 at 15:10
  • The consensus suggests that what I have in code is correct, although no one seems to be able to tell me why the view isn't being drawn when called from my controller's awakeFromNib method. I will consider this issue resolved since I will be learning about view controllers anyway. – subject_x Feb 01 '11 at 16:05

8 Answers8

17

To be even more specific to your question, the syntax would be

UIWindow* window = [UIApplication sharedApplication].keyWindow;

UIView *polygonView = [[UIView alloc] initWithFrame: CGRectMake ( 0, 0, 200, 150)];
//add code to customize, e.g. polygonView.backgroundColor = [UIColor blackColor];

[window addSubview:polygonView];
[polygonView release];

This is a pattern you will use for not only this but subviews afterwards. Also, another note is with many of the templates, the viewController is already set up with it's own view. When you want to make a custom view, you create it like above but instead of the method above you set the viewControllers view to the newly created view like so:

viewController.view = polygonView;

Good luck!

SushiGrass Jacob
  • 19,425
  • 1
  • 25
  • 39
  • I must be doing something wrong then. I have it exactly as you've wrote and my view isn't displaying. – subject_x Jan 27 '11 at 19:22
  • Hmmm… What happens if you comment out drawRect or specifically call it in initWithFrame with [self drawRect];? – SushiGrass Jacob Jan 30 '11 at 20:29
  • Nothing different happens if I don't override drawRect. If I call drawRect from the initWithFrame method I get an exception error: "reason: '-[PolygonView drawRect]: unrecognized selector sent to instance 0x4b58c70'" – subject_x Jan 31 '11 at 14:40
4

This is an old question, but I'm not sure he got the answer he expected - it sounds like he ran into the same problem I did where I created a UIViewController subclass, whacked a UIViewController in an interface builder nib but then couldn't figure out how to get the two working with one another.

If you made the nib seperately (so it wasn't made for you alongside your class) then you have to remember to click the UIViewController you placed in the interface builder, and then from the properties panel click the third tab button ('Custom Class'). The Class will be the default base class UIViewController etc - just open up this dropdown list and you'll see a list of all your custom subclasses, select it and volla - you've linked your custom element to the interface.

Hope that saves somebody the days it took me to figure out, I found some stupidly wonderful ways of getting around it until I realized the simple solution.

Rajneesh071
  • 30,846
  • 15
  • 61
  • 74
RoyalFool
  • 246
  • 2
  • 7
2

hi just add this code,

[window bringSubviewToFront:polygonView];

right after,
 [window addSubview:polygonView];
AJPatel
  • 2,291
  • 23
  • 42
2

You need to have a view (or window) to add a subview to. The normal syntax is like this:

UIView *newView = [[UIView alloc] initWithFrame:mainView.bounds];
[mainView addSubview:newView];
[newView release];

Of course, if you have a custom object that inherits from UIView, you would use that instead of UIView. When you start a new project, create a "View based application", that will start you off with a view controller with an associated view (which can be accessed with "CustomViewController.view", which would replace "mainView" in the code snippet above).

If you want to create the view programmatically when the app starts, put the code in the "- (void)viewDidLoad" method of your view controller.

Ned
  • 6,280
  • 2
  • 30
  • 34
  • I know a View controller would be the way to go, but in this particular assignment there's only one model class, one controller class, and the custom view class. Are you saying I would have to add my view object to the main window? How and where would I do that? – subject_x Jan 27 '11 at 18:18
0

call

[super drawRect];

before your custom code in drawRect: body.

nickolay
  • 3,643
  • 3
  • 32
  • 40
0

Somewhere in your active controller class, you can add a custom view to the current top level view.

[ myCurrentTopView addSubview: myNewCustomView ];

It helps to allocate and initialize this custom view first.

Then, you can trigger some drawing in this custom view's drawRect by doing a:

[ myNewCustomView setNeedsDisplay ];
hotpaw2
  • 70,107
  • 14
  • 90
  • 153
  • My current topview is the main window. The main window is not an object in my controller class, so how would I set my view as a subview ([window addSubView:...] doesn't work). – subject_x Jan 27 '11 at 18:35
0

Did you set the background color of your view to something distinguishable?

Are you sure your view doesn't display, or is it just that you can't see it? Put an NSLog in the drawRect: method of your view (if you use a custom view class).

fzwo
  • 9,842
  • 3
  • 37
  • 57
  • Yes, I tried setting my initial background color to black just to see if I can see a white or gray view show up, which didn't. I also put an NSLog message in drawRect and iniWithFrame which also didn't show in the console. I don't think my view is being initialized even though I have polygonView = [polygonView initWithFrame:CGRectMake(0, 10, 320, 480)]; in the awakeFromNib method of my controller. – subject_x Jan 27 '11 at 21:13
  • I take that back about the view not initializing. It is and the NSLog message in iniWithFrame is showing up. It's just the NSLog message in drawRect that isn't showing up. I can see that my data in my model is getting passed to my view correctly. I just can't figure why the window won't display my view. – subject_x Jan 27 '11 at 21:32
  • Maybe a little more code would help us analyze the situation then. – fzwo Jan 28 '11 at 06:46
0

I had a very similar problem recently and here's what worked for me: It seems that when starting with an 'empty application' in Xcode 4.3.2 you have to set your view as the root view your main window using the setRootViewController method instead of addSubview. So:

// Initialize myView and then
[window setRootViewController:myView];
// instead of [window addSubview:myView];
// the rest as normal...
[window makeKeyAndVisible];

After that you can use the addSubview method to add additional views.

Matjan
  • 3,591
  • 1
  • 33
  • 31