Why does this code from iPhone Developer's Cookbook work? - iphone

I've been trying out some of the view code from Erica Sadun's book "The iPhone Developer's Cookbook" and found some code I don't understand. Here's the code for a loadView method:
- (void)loadView
{
// Create the main view
UIView *contentView = [[UIView alloc] initWithFrame:
[[UIScreen mainScreen] applicationFrame]];
contentView.backgroundColor = [UIColor whiteColor];
self.view = contentView;
[contentView release];
// Get the view bounds as our starting point
CGRect apprect = [contentView bounds];
// Add each inset subview
UIView *subview = [[UIView alloc]
initWithFrame:CGRectInset(apprect, 32.0f, 32.0f)];
subview.backgroundColor = [UIColor lightGrayColor];
[contentView addSubview:subview];
[subview release];
}
My question is why does she release contentView, but then use it again in [contentView addSubview:subview]? Has self.view = contentView retained contentView?

If you look in the documentation for UIViewController, you'll see that the view property is declared as:
#property(nonatomic, retain) UIView *view;
This means that when you use the setView: method (or use .view on the left hand side of the =), then whatever value you pass in will be retained. So, if you go through the code and look at retain counts, you'll get this:
- (void)loadView {
// Create the main view
UIView *contentView = [[UIView alloc] initWithFrame:
[[UIScreen mainScreen] applicationFrame]]; //retain count +1
contentView.backgroundColor = [UIColor whiteColor]; //retain count +1
self.view = contentView; //retain count +2
[contentView release]; //retain count +1
// Get the view bounds as our starting point
CGRect apprect = [contentView bounds];
// Add each inset subview
UIView *subview = [[UIView alloc]
initWithFrame:CGRectInset(apprect, 32.0f, 32.0f)];
subview.backgroundColor = [UIColor lightGrayColor];
[contentView addSubview:subview];
[subview release];
}
I'd say that the really interesting thing is that after releasing contentView, we can still send messages to it, because the object living at the end of contentView's pointer still exists (since it was retained by calling setView:).

If u declare ur property like so
#property(nonatomic,retain) ...
TheN yes the property is retained when assigned. that is probably what's going on

Related

Subviews in UIView Hierarchy not displaying subviews

When this Action is executed it displays totally black view screen with toolbar
- (void)displayviewsAction:(id)sender
{
self.view = [[[UIView alloc] initWithFrame:[[UIScreen mainScreen] bounds]]autorelease];
self.view.frame = CGRectMake(0, 0, 320, 480);
[self.view addSubview:toolbar];
UIView *viewController = [[UIView alloc] init];
UIView *secondController = [[UIView alloc] init];
[self.view insertSubview:viewController atIndex:1];
[self.view insertSubview:secondController atIndex:2];
NSLog(#"%d", [[self.view subviews] indexOfObject:viewController]); // Is 1
NSLog(#"%d", [[self.view subviews] indexOfObject:secondController]); // Is 2
[self.view bringSubviewToFront:viewController];
NSLog(#"%d", [[self.view subviews] indexOfObject:viewController]);
[self.view sendSubviewToBack:viewController];
NSLog(#"%d", [[self.view subviews] indexOfObject:viewController]);
[self.view bringSubviewToFront:secondController];
NSLog(#"%d", [[self.view subviews] indexOfObject:secondController]);
SecondViewController * secondController = [[[SecondViewController alloc] init]autorelease];
secondController.view.frame = CGRectMake(0, 0, 320, 480);
[self.view addSubview:secondController.view];
[self.view addSubview:toolbar];
}
Any ideas why the view is appearing as totally black with toolbar.
The default background color of views is nil, which is a transparent background.
If you have nothing in any of the views and set no background color for any of them, the default background of the window or the device will show through. I didn't see it in the documentation, but I am assuming it is black.
Also, you have defined UIView pointers, but named them with the word "controller". This can contribute to mistakes since a UIViewController is an entirely different object. The UIViewController contains a UIView and interacts with it, but it is not a UIView, nor does it inherit from one.

adding UIView to UIViewController

I need to add a Button or a label to a UIView and add it to my UIViewController. I did the following but it only crashed the program.
UIView *myview = [[UIView alloc] initWithFrame:CGRectMake(100, 100, 0, 300)] ;
[myview addSubview:myButton];
[self.view addSubview:myView];
The code crashes. Why is that?
You set your myview's width to 0.
You sure you created "myButton"?
You create myview but you add my*V*iew as subview. Is there any warning?
The first step you need to take is:
Make Sure you have allocated & initialized UIButton object with "initWithFrame" method.
provide a width to your UIView in "initWithframe" method, So that it can be seen.
Now use your [self.view addSubview:myView];
Please let me know if it is useful.
Use:
//Assuming that myview should have the size of the main view:
UIView *myview = [[UIView alloc] initWithFrame:self.view.bounds];
[myview addSubview:myButton]; //Whatever ...
[self.view addSubview:myview]; //There was a typo in this line
If this code block is in the init or loadView of viewcontroller, this will crash.
Make sure you have created a view for view controller in this case before adding views to self.view
UIView *aView = [[UIView alloc] initWithFrame:[[UIScreen mainScreen] applicationFrame]];
self.view = aView;
[aView release];
myButton = [[UIButton alloc] init....
.....
UIView *myView = [[UIView alloc] initWithFrame:CGRectMake(100, 100, 0, 300)] ;
[myView addSubview:myButton];
[self.view addSubview:myView];
Try updating the view with the following:
[myview setNeedsDisplay];
and remove the second call to addSubView (which is probably causing the crash):
[self.view addSubview:myView];

Why am i getting a black frame and not the picker?

I have this very simple code or at least i think it's simple.
// Implement loadView to create a view hierarchy programmatically, without using a nib.
- (void)loadView {
CGRect rect = CGRectMake(0.0f, 20.0f, 320.0f, 216.0f);
UIPickerView *myPickerView = [[UIPickerView alloc] initWithFrame:rect];
self.view = myPickerView;
[myPickerView release];
}
I am running a general View Based template with XCode. I can see the loadView getting called but i get an black frame instead of the UIPickerView.
What am i doing wrong ?
/donnib
Have you implemented the picker's datasource methods? You need it otherwise it won't show.
Link to Apple Documentation here: http://developer.apple.com/library/ios/#DOCUMENTATION/iPhone/Reference/UIPickerViewDataSource_Protocol/Reference/Reference.html#//apple_ref/occ/intf/UIPickerViewDataSource
You've forgotten to set the UIPickerView's delegate to your current view. Add:
myPickerView.delegate = self;
...following your initialization and before your view. And of course, make sure you set up your header file as a UIPickerView delegate and implement the dataSource methods.
Try this:
UIView *contentView = [[UIView alloc] initWithFrame: [[UIScreen mainscreen] bounds]];
UIPickerView *pickerView = [[UIPickerView alloc] initWithFrame: CGRectZero];
CGSize pickerSize = [pickerView sizeThatFits: CGSizeZero];
pickerView.frame = [self pickerFrameWithSize: pickerSize];
[pickerView setShowsSelectionIndicator: YES];
[contentView addSubview: pickerView];
[pickerView release];
[self setView: contentView];
[contentView release];
Instead of overriding -loadView, you should override -viewDidLoad. Once the view has loaded you'll create the picker and add it as a subview of the view owned by the view controller.
- (void)viewDidLoad
{
[super viewDidLoad];
CGRect rect = CGRectMake(0.0f, 20.0f, 320.0f, 216.0f);
UIPickerView *myPickerView = [[UIPickerView alloc] initWithFrame:rect];
[self.view addSubview:myPickerView];
[myPickerView release];
}

Why does initWithFrame have the wrong frame value?

I have a subclass of UIButton called INMenuCard and I am overriding the initWithFrame to include an activity indicator. The menuCard places correctly but any internal reference to "frame" give me "inf,inf,0,0" which means my activityIndicator subview is not placed correctly. What might I be missing?
#implementation INMenuCard
- (id)initWithFrame:(CGRect)frame
{
if (self = [super initWithFrame:frame])
{
CGRect innerFrame = CGRectInset(frame, 50.0f, 100.0f);
activityIndicator = [[UIActivityIndicatorView alloc]
initWithFrame:innerFrame];
activityIndicator.activityIndicatorViewStyle = UIActivityIndicatorViewStyleWhite;
[self addSubview:activityIndicator];
}
return self;
}
I am instantiating INMenuCard with (debugging shows the CGRect values are correct):
CGRect cardFrame = CGRectMake(cardX, cardStartY, cardWidth, cardHeight);
INMenuCard *menuCard = [[INMenuCard buttonWithType:UIButtonTypeCustom] initWithFrame:cardFrame];
[theView addSubView:menuCard];
Should you be calling initWithFrame on something that is already init'ed?
It seems to me that the line [INMenuCard buttonWithType:UIButtonTypeCustom] is calling the UIButton's shortcut which does the [[UIButton alloc] init] for you.

Set up view in code that changes with orientation

I have set up an application and used some of the basic code from "The iPhone Developer's Cookbook" to create a simple view. The application works correctly in portrait mode, but when it is rotated, the dimensions of the boxes stay the same. Here is my code:
- (void)loadView {
//Create the full application frame (minus the status bar) - 768, 1004
CGRect fullRect = [[UIScreen mainScreen] applicationFrame];
//Create the frame of the view ie fullRect-(tabBar(49)+navBar(44)) - 768, 911
CGRect viewRect = CGRectMake(0, 64, fullRect.size.width, fullRect.size.height-93.0);
//create the content view to the size
contentView = [[UIView alloc] initWithFrame:viewRect];
contentView.backgroundColor = [UIColor whiteColor];
// Provide support for autorotation and resizing
contentView.autoresizesSubviews = YES;
contentView.autoresizingMask = (UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight);
self.view = contentView;
[contentView release];
// reset the origin point for subviews. The new origin is 0,0
viewRect.origin = CGPointMake(0.0f, 0.0f);
// Add the subviews, each stepped by 32 pixels on each side
UIView *subview = [[UIView alloc] initWithFrame:CGRectInset(viewRect, 32.0f, 32.0f)];
subview.backgroundColor = [UIColor lightGrayColor];
[contentView addSubview:subview];
[subview release];
subview = [[UIView alloc] initWithFrame:CGRectInset(viewRect, 64.0f, 64.0f)];
subview.backgroundColor = [UIColor darkGrayColor];
[contentView addSubview:subview];
[subview release];
subview = [[UIView alloc] initWithFrame:CGRectInset(viewRect, 96.0f, 96.0f)];
subview.backgroundColor = [UIColor blackColor];
[contentView addSubview:subview];
[subview release];
}
Is there any way to have this reload with the new dimensions when it is rotated or a better way of accommodating the orientation change?
Thanks
JP
I may be misunderstanding your problem. By "boxes", do you mean the subviews?
If so, the subviews will retain their apparent dimensions when rotated because they are squares.
In any case, viewDidLoad is only called when a view is first initialized, usually from a nib. If you need to make changes to a view when it rotates, you need to make the changes in willRotateToInterfaceOrientation:duration: and/or didRotateFromInterfaceOrientation:.
To change the dimensions of any view, simply reset its frame.
object.autoresizingMask=UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleBottomMargin|UIViewAutoresizingFlexibleHeight|UIViewAutoresizingFlexibleWidth;