UIView is never rendered if added as subview in viewDidLoad - ios

I'm trying to add a subview to a view controller programatically, but it seems like if I add the subview in the viewDidLoad of the view controller whatever I have added as subview in the view itself is not rendered in the view controller.
But if I move the [self.view addSubview:myUIView] in the init method of the view controller, everything is rendered.
Also, if I call the same methods in the viewDidAppear I get all the elements rendered, but it's right after the view controller was displayed, and I can see when the elements are rendered in the view controller.
This would be my view controller:
//interface
#class RLJSignInView;
#protocol RLJSignInViewControllerDelegate;
#interface RLJSignInViewController : UIViewController <UITextFieldDelegate>
#property (nonatomic, readwrite) RLJSignInView *signInView;
#property (nonatomic, assign) id<RLJSignInViewControllerDelegate> delegate;
#end
//implementation
#import "RLJSignInViewController.h"
#import "RLJSignInView.h"
#import "RLJSignInViewControllerDelegate.h"
#import "UIColor+RLJUIColorAdditions.h"
#implementation RLJSignInViewController
- (id)init
{
self = [super init];
if (self) {
_signInView = [[RLJSignInView alloc] initWithFrame:self.view.bounds];
[self.view addSubview:self.signInView];
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
NSLog(#"%#", self.signInView);
[self.view setBackgroundColor:[UIColor rgbWithRed:250 green:250 blue:250]];
}
#end
And this would be my view:
//interface
#interface RLJSignInView : UIView
#property (strong, nonatomic, readwrite) UITextField *username;
#property (strong, nonatomic, readwrite) UITextField *password;
#property (strong, nonatomic, readwrite) UIButton *signIn;
#property (strong, nonatomic, readwrite) UIButton *signUp;
#end
//implementation
#import "RLJSignInView.h"
#import "UITextField+RLJUITextFieldAdditions.h"
#import "UIButton+RLJUIButtonAdditions.h"
#implementation RLJSignInView
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
CGRect usernameInputFrame = CGRectMake(10.0, 40.0, self.bounds.size.width - 20, 40);
CGRect passwordInputFrame = CGRectMake(10.0, 79.0, self.bounds.size.width - 20, 40);
CGRect signInButtonFrame = CGRectMake(10.0, 160, self.bounds.size.width - 20, 40);
CGRect signUpButtonFrame = CGRectMake(10.0, 220, self.bounds.size.width - 20, 40);
UIView *usernameInputLeftView = [[UIView alloc] initWithFrame:CGRectMake(0.0, 0.0, 10.0, 40)];
UIView *passwordInputLeftView = [[UIView alloc] initWithFrame:CGRectMake(0.0, 0.0, 10.0, 40)];
self.username = [[UITextField alloc] initWithFrame:usernameInputFrame
textAlignment:NSTextAlignmentLeft
textColor:[UIColor blackColor]
clearButton:UITextFieldViewModeWhileEditing
leftView:usernameInputLeftView
placeholder:#"Username"
backgroundColor:[UIColor whiteColor]
strokeWidth:2.0
strokeColor:[UIColor lightGrayColor]
keyboardType:UIKeyboardTypeEmailAddress
byRoundingCorners:UIRectCornerTopLeft | UIRectCornerTopRight
cornerRadii:CGSizeMake(4.0, 4.0)
secure:NO];
self.password = [[UITextField alloc] initWithFrame:passwordInputFrame
textAlignment:NSTextAlignmentLeft
textColor:[UIColor blackColor]
clearButton:UITextFieldViewModeWhileEditing
leftView:passwordInputLeftView
placeholder:#"Password"
backgroundColor:[UIColor whiteColor]
strokeWidth:2.0
strokeColor:[UIColor lightGrayColor]
keyboardType:UIKeyboardTypeDefault
byRoundingCorners:UIRectCornerBottomLeft | UIRectCornerBottomRight
cornerRadii:CGSizeMake(4.0, 4.0)
secure:YES];
self.signIn = [[UIButton alloc] initWithFrame:signInButtonFrame
title:#"Sign In"
colorNormal:[UIColor whiteColor]
colorHighlighted:[UIColor whiteColor]
colorDisabled:[UIColor whiteColor]
backgroundNormal:[UIColor colorWithRed:82 / 255.0 green:156 / 255.0 blue:201 / 255.0 alpha:1.0]
cornerRadius:4.0];
self.signUp = [[UIButton alloc] initWithFrame:signUpButtonFrame
title:#"Sign Up"
colorNormal:[UIColor blackColor]
colorHighlighted:[UIColor blackColor]
colorDisabled:[UIColor blackColor]
backgroundNormal:[UIColor whiteColor]
cornerRadius:4.0];
[self addSubview:self.username];
[self addSubview:self.password];
[self addSubview:self.signIn];
[self addSubview:self.signUp];
}
return self;
}
#end
I'm not sure what I could do about it, but I know for sure that I would not like the view to be added to the subview on initialisation.
Or maybe I'm doing the rendering of the subviews of the view wrong. I would appreciate some input on this matter if anyone encountered the same thing or if noticed that I messed up something.

Don't call self.view from inside your init method. This will trigger viewDidLoad being called before your init method even returns, which is incorrect behavior.
Instead, follow this pattern:
create your objects (properties / instance variables) in init, or by using lazy instantiation
add the subviews in viewDidLoad
set the frames in viewWillLayoutSubviews
This pattern will avoid bugs like the one you posted here, and set you up for success handling rotation and resizing events in the future.

The key might be you are using self.view.bounds too early. It might work when you provide an initial size frame (like IB would do).
init is too early. The view controller is initializing, the view is not loaded yet, which means there's no view and the bounds will return CGRectZero.
viewDidLoad is also too early to rely on the view's bounds. The view is just loaded, it does not have a superview yet and might be resized later.
viewWillAppear is the first moment you can rely on the view's bounds. Since it will be resized according to the autoresizingmasks or autolayout constraints.
You can add the subview in viewDidLoad but you you should provide an initial frame (and you set the correct autoresizingmasks or constraints) it should all work fine.

Related

TabViewController setting UINavigationBar

I am trying to programatically setup my UINavigationBar. I have setup the NavBar for each tab in interface builder and it inherits from my GenericTabUiNavBar in interface builder.
However when I run the app, the GenericTabUiNavBar is not loaded with its elements into the UINavBar.
Here is my GenericTabUiNavBar code:
.h
#import <UIKit/UIKit.h>
#interface GenericTabUiNavBar : UINavigationBar
#property (nonatomic, strong) UILabel *firstLetter;
#property (nonatomic, strong) UILabel *secondLetter; //need two labels
#property (nonatomic,strong) UIButton *leftSideButton;
#property (nonatomic,strong) UIButton *rightSideButton;
#end
.m
#implementation GenericTabUiNavBar
#synthesize firstLetter;
#synthesize secondLetter;
#synthesize leftSideButton;
#synthesize rightSideButton;
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self)
{
// Initialization code
//r g b
//Yellow Color = 255,219,17
UIColor *yellowColor = [[UIColor alloc] initWithRed:255 green:219 blue:17 alpha:1];
UIColor *blueColor = [[UIColor alloc] initWithRed:1 green:129 blue:200 alpha:1];
UIFont *fontFaceAndSize = [UIFont fontWithName:#"HelveticaNeue" size:36];
//self
self.frame = CGRectMake(0, 20, 320, 44);
self.backgroundColor = blueColor;
self.barTintColor = blueColor;
//x.108 y.31
//w.15 / y.21
CGRect firstLetterRect = CGRectMake(108, 31, 15, 21);
self.firstLetter = [[UILabel alloc] initWithFrame:firstLetterRect];
firstLetter.text = #"An";
firstLetter.font = fontFaceAndSize;
firstLetter.textColor = [UIColor whiteColor];
//128 31
//22 21
CGRect secLetterRect = CGRectMake(108, 31, 15, 21);
self.secondLetter = [[UILabel alloc] initWithFrame:secLetterRect];
secondLetter.text = #"APP";
secondLetter.font = fontFaceAndSize;
secondLetter.textColor = yellowColor;
//tex pos =
self.leftSideButton = [[UIButton alloc] initWithFrame:CGRectMake(20, 29, 30, 26)];
self.rightSideButton = [[UIButton alloc] initWithFrame:CGRectMake(207, 29, 30, 26)];
[leftSideButton setImage:[UIImage imageNamed:#"anImg.png"] forState:UIControlStateNormal];
[rightSideButton setImage:[UIImage imageNamed:#"otherImg.png"] forState:UIControlStateNormal];
[self addSubview:leftSideButton];
[self addSubview:firstLetter];
[self addSubview:secondLetter];
[self addSubview:rightSideButton];
}
return self;
}
/*
// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
- (void)drawRect:(CGRect)rect
{
// Drawing code
}
*/
#end
In my TabViewController I call it by hooking it up in interface builder. Why does this not load?
When controllers are loaded from storyboard or xib. The init method
- (id)initWithCoder:(NSCoder *)decoder
is called instead of the
- (instancetype)initWithNibName:(NSString *)nibName
bundle:(NSBundle *)nibBundle
as for views the reason might be the same

Add UIView and UILabel to UICollectionViewCell

I am using GitHub project https://github.com/mayuur/MJParallaxCollectionView
I am trying to add a UIView and UILabel to the cells being displayed. I have tried so many solutions it would probably just be easier to ask someone how to do it.
So with that can someone add a UIView and UILabel to the UICollectionView displaying some text? This can be done programmatically or via storyboard, whichever suits your style.
I tried adding related logic in MJCollectionViewCell.m setupImageView method. Also, tried MJRootViewController cellForItemAtIndexPath method. But I still can't get the UIView and UILabel to display over the UIImage object in MJCollectionViewCell.
#property (nonatomic, strong, readwrite) UIImage *image;
MJCollectionViewCell.h
//
// MJCollectionViewCell.h
// RCCPeakableImageSample
//
// Created by Mayur on 4/1/14.
// Copyright (c) 2014 RCCBox. All rights reserved.
//
#import <UIKit/UIKit.h>
#define IMAGE_HEIGHT 200
#define IMAGE_OFFSET_SPEED 25
#interface MJCollectionViewCell : UICollectionViewCell
/*
image used in the cell which will be having the parallax effect
*/
#property (nonatomic, strong, readwrite) UIImage *image;
/*
Image will always animate according to the imageOffset provided. Higher the value means higher offset for the image
*/
#property (nonatomic, assign, readwrite) CGPoint imageOffset;
//#property (nonatomic,readwrite) UILabel *textLabel;
#property (weak, nonatomic) IBOutlet UILabel *textLabel;
#property (weak, nonatomic) IBOutlet UIImageView *cellImage;
#property (nonatomic,readwrite) NSString *text;
#property(nonatomic,readwrite) CGFloat x,y,width,height;
#property (nonatomic,readwrite) NSInteger lineSpacing;
#property (nonatomic, strong) IBOutlet UIView* overlayView;
#end
MJCollectionViewCell.m
// MJCollectionViewCell.m
// RCCPeakableImageSample
//
// Created by Mayur on 4/1/14.
// Copyright (c) 2014 RCCBox. All rights reserved.
//
#import "MJCollectionViewCell.h"
#interface MJCollectionViewCell()
#property (nonatomic, strong, readwrite) UIImageView *MJImageView;
#end
#implementation MJCollectionViewCell
- (instancetype)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) [self setupImageView];
return self;
}
- (id)initWithCoder:(NSCoder *)aDecoder {
self = [super initWithCoder:aDecoder];
if (self) [self setupImageView];
return self;
}
/*
// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
- (void)drawRect:(CGRect)rect
{
// Drawing code
}
*/
#pragma mark - Setup Method
- (void)setupImageView
{
// Clip subviews
self.clipsToBounds = YES;
/*
// Add image subview
self.MJImageView = [[UIImageView alloc] initWithFrame:CGRectMake(self.bounds.origin.x, self.bounds.origin.y, self.bounds.size.width, IMAGE_HEIGHT)];
self.MJImageView.backgroundColor = [UIColor redColor];
self.MJImageView.contentMode = UIViewContentModeScaleAspectFill;
self.MJImageView.clipsToBounds = NO;
[self addSubview:self.MJImageView];
*/
//New Code in method
// Add image subview
self.MJImageView = [[UIImageView alloc] initWithFrame:CGRectMake(self.bounds.origin.x, self.bounds.origin.y, self.bounds.size.width, IMAGE_HEIGHT)];
self.MJImageView.backgroundColor = [UIColor redColor];
self.MJImageView.contentMode = UIViewContentModeScaleAspectFill;
self.MJImageView.clipsToBounds = NO;
//self.overlayView.backgroundColor = [UIColor colorWithWhite:0.0f alpha:0.4f];
// UIView *anotherView = [[UIView alloc]initWithFrame:CGRectMake(0.0, 0.0, 20.0, 20.0)];
// UILabel *label = [[UILabel alloc]initWithFrame:CGRectMake(0.0, 0.0, 50.0, 20.0)];
// label.text = #"Hello";
// [anotherView addSubview:label];
[self addSubview:self.MJImageView];
[self addSubview:self.overlayView];
[self addSubview:self.textLabel];
}
# pragma mark - Setters
- (void)setImage:(UIImage *)image
{
// Store image
self.MJImageView.image = image;
// Update padding
[self setImageOffset:self.imageOffset];
}
- (void)setImageOffset:(CGPoint)imageOffset
{
// Store padding value
_imageOffset = imageOffset;
// Grow image view
CGRect frame = self.MJImageView.bounds;
CGRect offsetFrame = CGRectOffset(frame, _imageOffset.x, _imageOffset.y);
self.MJImageView.frame = offsetFrame;
}
//This was added from MPSkewed may need to remove if not called.
- (void)setText:(NSString *)text{
_text=text;
if (!self.textLabel) {
CGFloat realH=self.height*2/3-self.lineSpacing;
CGFloat latoA=realH/3;
// self.textLabel=[[UILabel alloc] initWithFrame:CGRectMake(10,latoA/2, self.width-20, realH)];
self.textLabel.layer.anchorPoint=CGPointMake(.5, .5);
self.textLabel.font=[UIFont fontWithName:#"HelveticaNeue-ultralight" size:38];
self.textLabel.numberOfLines=3;
self.textLabel.textColor=[UIColor whiteColor];
self.textLabel.shadowColor=[UIColor blackColor];
self.textLabel.shadowOffset=CGSizeMake(1, 1);
self.textLabel.transform=CGAffineTransformMakeRotation(-(asin(latoA/(sqrt(self.width*self.width+latoA*latoA)))));
[self addSubview:self.textLabel];
}
self.textLabel.text=text;
}
#end
In the .h of the cell:
#property (strong, nonatomic, readonly) UILabel *label
In the .m of the cell:
#property (strong, nonatomic, readwrite) UILabel *label
In the setupImageView method (which you should probably rename to be more generic), after the image view is created, something like this:
self.label = [[UILabel alloc] initWithFrame:someFrame]; // or CGRectZero if you are using auto layout
self.label.textColor = ...; // any other setup you want to do
[self addSubview:self.label];
self.label.frame = ...; // or set it up using auto layout
And in your data source’s -collectionView:cellForItemAtIndexPath:
cell.label.text = #"some text";
That is a simple approach. In practice, I would probably expose a property for the string only, not the whole label, but that depends on what you are doing and how much control you need.

addSublayer doesn't add any sublayer on the view

I was following a tutorial on a Core Animation book and I tried to do the following.
#interface ViewController ()
#property (nonatomic, weak) IBOutlet UIView * layerView;
#property (nonatomic, weak) CALayer *blueLayer;
#end
#implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
self.blueLayer = [CALayer layer];
self.blueLayer.frame = CGRectMake(50.0f, 50.0f, 100.0f, 100.0f);
self.blueLayer.backgroundColor = [UIColor blueColor].CGColor;
[self.layerView.layer addSublayer: self.blueLayer];
}
...
#end
According to the book, the code above should print a blue layer on the screen in the middle on top of layerView. But, I can only see layerView and blueLayer is no where to be seen. Does anyone know what is happening? I'm lost.
You should be getting a warning on this line
self.blueLayer = [CALayer layer];
Since self.bluelayer is a weak pointer, ARC will discard the object as soon as it's created. The property should be declared strong.

UIView is retaining subviews after dealloc ARC

I have a problem with one of my views retaining its subviews. The main view displays 'tables' in a restaurant, and loads a subview to display this 'table'.
When the main view is deallocated, the tables seem to remain allocated to memory. I have searched everywhere to try and find a solution to this as I just can't seem to fix it myself.
Firstly the code for the 'table' view:
#protocol tableDelegate <NSObject>
#required
- (void)tablePress:(id)sender;
- (void)tableSelect:(id)sender;
#end
#interface tablevw : UIView
{
CGPoint currentPoint;
}
-(void)changeOrderImage;
-(id)initWithFrame:(CGRect)frame teststring:(NSString *)ts;
#property (nonatomic, weak) IBOutlet UIView *view;
#property (nonatomic, weak) IBOutlet UILabel *numberLabel;
#property (nonatomic, weak) IBOutlet UILabel *nameLabel;
#property (nonatomic) BOOL isEdit;
#property (nonatomic) BOOL hasOrder;
#property (nonatomic, strong) NSMutableDictionary * orderNumbers;
#property (nonatomic) int orderNumber;
#property (nonatomic, strong) NSString *teststring;
#property (nonatomic, weak) IBOutlet UIImageView *tableImage;
#property (nonatomic, weak) id<tableDelegate> delegate;
#end
And the init method for the view:
- (id)initWithFrame:(CGRect)frame teststring:(NSString *)ts{
self = [super initWithFrame:frame];
if (self) {
orderNumbers = [[NSMutableDictionary alloc]init];
isRemote = FALSE;
NSString *filePath = [[NSBundle mainBundle] pathForResource:#"tabletopRound" ofType:#"png"];
UIImageView * iV =[[UIImageView alloc] initWithImage:[[UIImage alloc] initWithContentsOfFile:filePath]];
self.tableImage= iV;
tableImage.frame = CGRectMake(0, 0, 121, 121);
locked = FALSE;
[self addSubview:tableImage];
UITapGestureRecognizer *doubleTapGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(doubleTap)];
doubleTapGestureRecognizer.numberOfTapsRequired = 2;
[self addGestureRecognizer:doubleTapGestureRecognizer];
UILabel * label = [[UILabel alloc] initWithFrame:CGRectMake(35, 50, 48, 20)];
numberLabel = label;
[numberLabel setTextColor:[UIColor blackColor]];
[numberLabel setBackgroundColor:[UIColor clearColor]];
[numberLabel setText:ts];
[self addSubview:numberLabel];
UILabel * labelTwo = [[UILabel alloc] initWithFrame:CGRectMake(24, 123, 70, 20)];
nameLabel = labelTwo;
[nameLabel setTextColor:[UIColor whiteColor]];
[nameLabel setBackgroundColor:[UIColor clearColor]];
[self addSubview:nameLabel];
self.userInteractionEnabled = YES;
self.tag = [ts intValue];
}
return self;
}
Finally, in the 'main' view the tables are added like so:
NSString *myString = [results stringForColumn:#"table_number"];
tablevw * tableView = [[tablevw alloc] initWithFrame:CGRectMake(x-60.5, y-60.5, 121, 121) teststring:myString];
tableView.delegate = self;
[self.view addSubview: tableView];
The delegate is set to Nil when the main view is dealloced. I have over ridden the dealloc method to log the dealloc calls to me - it is being called on the 'main' view but not on the 'table' view.
Thanks for your help
In the dealloc method try
for (UIView *view in [self.view subviews]) {
[view removeFromSuperview];
}
It would be even better if u can try
[tablevw removeFromSuperview], tablevw = nil;
I can see that your tablevw has a week reference to his delegate and that should be enough for to release the parent, but just for argue sake trie to nil tablevws delegate. Create an array of tablevw instances you created (or tag them as already suggested), then before you release parent remove them from superview, set their delegate to nil and kill the array. See what happenes, maybe that will help...

UIView setNeedsDisplay doesn't work

Simple code is here:
Custom MyButton.h
#interface PaiLifeReadingListButton : UIButton
#property (strong, nonatomic) UIImageView *logoImageView;
#end
Custom MyButton.m
#implementation PaiLifeReadingListButton
#synthesize logoImageView = _logoImageView;
-(id)init
{
_logoImageView = [[UIImageView alloc] initWithFrame:CGRectMake(33.0, 20.0, 80.0, 80.0)];
[_logoImageView setImage:[UIImage imageNamed:#"pic"]];
[self addSubview: _logoImageView];
}
#end
Custom MyView.h:
#property (strong, nonatomic) Mybutton *mybutton;
Custom MyView.m:
-(id) init
{
myButton = [[MyButton alloc] init];
[self addSubview:myButton];
}
ViewController.m:
#synthesize myView;
- (void)viewDidLoad
{
myView = [[Myview alloc] init];
[myView.myButton addTarget:self action:#selector(pressed:) forControlEvents:UIControlEventTouchDown];
self.view = myView;
}
-(void)pressed : (MyButton *)button
{
UIImageView *newImageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"other-pic"] highlightedImage:nil];
myView.myButton.logImageView = newImageView;
[self.view setNeedsDisplay]; //----this does not work
}
When I press the button, the imageview does not change. How can I fix this?
Thank you very much!
First thing , you don't need setNeedsDisplay here. setNeedsDisplay is used for redrawing the view (it internally calls the drawRect: method of the view if required) which is not what you want.
Second, you have given the class of your button as MyButton,but in the actual .h and .m files, it is given as #interface PaiLifeReadingListButton and #implementation PaiLifeReadingListButton respectively.
Another thing, the view and button is not initialized with a frame. But I assume you have done that already, since your only problem is the image view not changing.
In your code in pressed method you should change views in the hierarchy, but you change only the object member. You can do something like
myView.myButton.logImageView.image = [UIImage imageNamed:#"other-pic"];

Resources