Add a subclass of subview to a subclass of UIView - ios

I'm trying to do something very basic. I want to add a subView to my UIView subclass. I assume that I would put this in initWithFrame method as below, but view that are instances of this class do not draw this subview. What am I doing wrong?
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
redView = [[UIView alloc] initWithFrame:CGRectMake(10, 10, 20, 20)];
[redView setBackgroundColor:[UIColor redColor]];
[self addSubview:redView];
}
return self;
}
BTW redView is a property defined in the header of the sub class, like:
#property (strong, nonatomic) UIView *redView;
Thanks for reading!

You should place your initializing code inside:
- (id)initWithCoder:(NSCoder *)aDecoder { ... }
or
- (void)awakeFromNib { ... }
These methods are called when a view is loaded from nib. Don't forget to call [super ...] in the above methods.

Related

Custom UIButton's setIsSelected method not called

I have a custom class based on UIButton, and I have difficulties calling the custom setter method in this custom class. I will list the codes in these files:
CallMyMethod.h (subclass of UIButton)
CallMyMethod.m
CallOtherClassMethod.h (to call setter method in CallMyMethod)
CallOtherClassMethod.m
CallMyMethod.h
#interface CallMyMethod : UIButton
#property (nonatomic, setter=setIsSelected:) BOOL isSelected;
#property (nonatomic, retain) UIImageView *checkmarkImageView;
- (void)setIsSelected:(BOOL)aIsSelected; //this is unnecessary, I guess
#end
CallMyMethod.m
#implementation CallMyMethod
#synthesize isSelected = _isSelected;
#synthesize checkmarkImageView = _checkmarkImageView;
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code
[self loadView];
}
return self;
}
- (void) loadView
{
[self.checkmarkImageView setHidden:YES];
}
- (UIImageView *)checkmarkImageView
{
if (_checkmarkImageView == nil) {
UIImage *checkmarkImage = [UIImage imageNamed:#"checkmark.png"];
_checkmarkImageView = [[UIImageView alloc]initWithImage:checkmarkImage];
[_checkmarkImageView setFrame:CGRectMake(10, 10, 32, 32)];
[self addSubview:_checkmarkImageView];
}
return _checkmarkImageView;
}
- (void)setIsSelected:(BOOL)aIsSelected
{
_isSelected = aIsSelected;
[self.checkmarkImageView setHidden:!_isSelected];
[self addSubview:_checkmarkImageView];
}
#end
CallOtherClassMethod.h
#class CallMyMethod;
#interface CallOtherClassMethod : UIViewController
#property (nonatomic,retain) CallMyMethod *btnCMM;
#end
CallOtherClassMethod.m
#import "CallMyMethod.h"
#implementation CallOtherClassMethod
#synthesize btnCMM;
- (void)viewDidLoad
{
[super viewDidLoad];
self.btnCMM = [[CallMyMethod alloc]initWithFrame:CGRectMake(0, 30, 50, 70)];
//somewhere in my code I will add btnCMM to the view
[someView bringSubviewToFront: btnCMM];
[someView addSubview: btnCMM];
}
//somewhere where I pressed a button to trigger this method
- (IBAction) pressMe:(id)sender
{
NSLog(#"self.btnCMM %#", self.btnCMM); //returned as btnCMM is nil ?!
[self.btnCMM setIsSelected:YES];
}
#end
The issue lies in the program not able to run the codes in setIsSelected method, I have traced btnCMM to be nil in NSLog. I wonder why is this so, because when I call CallOtherClassMethod as a UIViewController, the viewDidLoad would have initialised my custom button. Am I doing something wrong here?
Why not override setSelected, which is a method on UIButton and then use button.selected = YES?
If you want to debug why your button becomes nil, implement dealloc in your UIButton subclass, put a breakpoint there, and see the stack trace to find the reason.

Add category to UITextView and Override it's init function while UITextView is in xib

I can't intercept the init function that's getting called when it's getting created inside of the xib file.
I want to add borderline to it when it gets created so that I won't need to add it manually.
.h:
#import <UIKit/UIKit.h>
#interface UITextView (FITAddBorderline)
- (id) init;
- (id) initWithFrame:(CGRect)frame;
#end
.m:
#import "UITextView+FITAddBorderline.h"
#implementation UITextView (FITAddBorderline)
- (id) init
{
self = [super init];
if (self) {
[self addBorderline];
}
return self;
}
- (id) initWithFrame:(CGRect)frame {
self = [super init];
if (self) {
self.frame = frame;
[self addBorderline];
}
return self;
}
- (void) addBorderline {
//To make the border look very close to a UITextField
[self.layer setBorderColor:[[[UIColor grayColor] colorWithAlphaComponent:0.5] CGColor]];
[self.layer setBorderWidth:2.0];
//The rounded corner part, where you specify your view's corner radius:
self.layer.cornerRadius = 5;
self.clipsToBounds = YES;
}
#end
Views that come from NIBs are initialized with initWithCoder:
- (id)initWithCoder:(NSCoder *)aDecoder
{
self = [super initWithCoder:aDecoder];
if (self)
{
[self addBorderline];
}
return self;
}
As a side note, I would recommend changing what you are doing and use a subclass instead of a category. You can get yourself into some trouble overriding methods in a category. See more info here.
You just need to implement the awakeFromNib method:
-(void)awakeFromNib
{
[super awakeFromNib];
[self addBorderline];
}

Why do both init functions get called

If I have a class that is setup like this to customize a UIView.
#interface myView : UIView
- (id)init {
self = [super init];
if(self){
[self foo];
}
return self;
}
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code
[self foo];
}
return self;
}
-(void) foo{
//Build UIView here
}
How come foo is called twice whether I use
myView *aView = [[myView alloc]init]];
or
myView *aView = [[myView alloc]initWithFram:aFrame];
UIView init calls UIView initWithFrame:. Since you override both, calling your init method results in your initWithFrame: method being called:
In other words: your init calls UIView init. UIView init calls initWithFrame:. Since you override initWithFrame:, your initWithFrame: is called which in turn calls UIView initWithFrame:.
The solution, since your initWithFrame: will always be called, is to remove the call to foo from your init method.

Not able to add subview to my UIView

I have a UIView element on the screen. It is connected by an IBOutlet radioButtonGroupView. I am trying to add a subview to that element and it is not working. The subview is never added.
Here is my code:
-(id) initWithCoder:(NSCoder *)aDecoder
{
self = [super initWithCoder:aDecoder];
UIView *subView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 100, 100)];
subView.backgroundColor = [UIColor yellowColor];
[self.radioButtonGroupView addSubview:subView];
return self;
}
You will probably be better off if you make this element a subclass of a UIViewController (instead of a UIView).
Then put the subview loading code inside viewDidLoad method.
- (void)viewDidLoad
{
[super viewDidLoad]; //not really needed but it doesn't hurt
UIView *subView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 100, 100)];
subView.backgroundColor = [UIColor yellowColor];
[self.radioButtonGroupView addSubview:subView];
}
EDIT:
You say that you don't get any frame information on self.radioButtonGroupView in your viewDidLoad. That is almost a certain sign that your IBOutlet is not properly connected to the element in InterfaceBuilder. You can always make a simple test:
- (void)viewDidLoad
{
[super viewDidLoad]; //not really needed but it doesn't hurt
NSLog (#"self.radioButtonGroupView: %#",self.radioButtonGroupView);
[self.radioButtonGroupView setHidden:YES];
}
If it is still shown - then it simply isn't properly connected. IB has it's ways. Simple
deletion of IBOutlet connection and reconnecting it again might do the trick. Also: it your radioButtonGroupView is not UIView but a subclass of UIView, make sure that it's header file is imported in your MyViewController.m file and class properly defined in .xib.

UIView addSubview and the subview isn't displayed

- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
HeadViewController *headViewController = [[HeadViewController alloc] initWithNibName:#"HeadViewController" bundle:nil];
UIView *view = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 320, 120)];
[view addSubview:headViewController.vew];
[self.view addSubview:view];
}
HeadViewController.h:
#interface HeadViewController : UIViewController
{
IBOutlet UIView *view;
}
#property (nonatomic, retain)IBOutlet UIView *view;
#end
and I connect the view to the file's owner.
And I can't see the headViewController.view.
First of all, you do not need to define the view outlet in the HeadViewController class. It is automatically inherited from the UIViewController super class.
Then, I suggest you to add directly the view of HeadViewController to your current view. Eg.
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
HeadViewController *headViewController = [[HeadViewController alloc] initWithNibName:#"HeadViewController" bundle:nil];
headViewController.view.frame = CGRectMake(0, 0, 320, 120);
[self.view addSubview:headViewController.view];
}
But, if you are using ARC (Automatic Reference Counting), the headViewController instance will probably be deallocated after the end of the viewDidLoad method. It is convenient (and I'd say it is compulsory) to assign that instance to a local variable in the controller you are currently displaying. This way you will be able to handle its view's components later if needed, the instance will be retained, and everything else will work perfectly. You should have something like:
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
self.headViewController = [[HeadViewController alloc] initWithNibName:#"HeadViewController" bundle:nil];
headViewController.view.frame = CGRectMake(0, 0, 320, 120);
[self.view addSubview:headViewController.view];
}
and
#interface MyController ()
#property (nonatomic, strong) HeadViewController *headViewController;
#end
in the hidden interface definition at the beginning of the .m class implementation file.
It looks like a typo - forgot the i in .view
[view addSubview:headViewController.vew];
i is missing in the syntax
[view addSubview:headViewController.view];

Resources