Subclassing a UIView, one method to setup whether initWithFrame: or awakeFromNib - uiview

When subclassing a UIView I tend to create a private method called 'setup', which I put into initWithFrame and awakeFromNib.
Is this what other people tend to do too? Or is there a method I don't know about that does what I'm looking to do.
I've been through the UIView class reference but I can't see anything, so just wondered what others do?

I actually avoid using -awakeFromNib and use -initWithCoder: instead. This is my typical UIView subclass setup:
- (id)initWithFrame:(CGRect)frame {
if (self = [super initWithFrame:frame]) {
[self _init];
}
return self;
}
- (id)initWithCoder:(NSCoder *)aDecoder {
if (self = [super initWithCoder:aDecoder]) {
[self _init];
}
return self;
}
- (id)init {
if (self = [super init]) {
[self _init];
}
return self;
}
- (void)_init {
}
I actually have a Snippet to do this too. I just type
init_view
And it generates all of the above.

Related

in Objc ,how to do it elegantly?

I wrote a subclass of UITextView ,to make the textView auto grow or shrink with the textView's content . Now ,I have to the textView's delegate to the subclass object it self (because i have to do something in - (void)textViewDidChange:(UITextView *)textView)
#implementation AutoGrowTextViewV2
- (instancetype) initWithCoder:(NSCoder *)aDecoder
{
self = [super initWithCoder:aDecoder];
if (self)
{
self.delegate = self;
}
return self;
}
- (CGSize)intrinsicContentSize
{
return [self sizeThatFits:CGSizeMake(self.bounds.size.width, MAXFLOAT)];
}
- (void)textViewDidChange:(UITextView *)textView
{
[self invalidateIntrinsicContentSize];
[self layoutIfNeeded];
}
But in practice , AutoGrowTextViewV2 always need to set it's delegate to other objects , so I had to write textViewDidChange codes in everywhere. how can i make this simple? maybe runtime forward or something?

How can I implement a UIViewcontroller thread safe singleton when I use storyboard?

I need that one ViewController of my app is a singleton. I'm using storyboard.
I used this code:
- (id)init
{
if (self = [super init]) {
}
return self;
}
static id s_singleton = nil;
+ (id) alloc {
if(s_singleton != nil)
return s_singleton;
return [super alloc];
}
- (id) initWithCoder:(NSCoder *)aDecoder {
if(s_singleton != nil)
return s_singleton;
self = [super initWithCoder:aDecoder];
if(self) {
s_singleton = self;
}
return self;
Maybe it is not thread safe because it creates two different instance of the class...
How can I resolve this problem?

Which init method for UIView will be called when using drag and drop in xib file

here is the custom collection view,and below label is the (rating view i design).
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
[self initGrayStarView];
[self initYellowStarView];
[self initRatingLabel];
}
return self;
}
but i find that it every time the rating view didn't appear(image view and label did). then i found it's because that i didn't call the init method for rating view,so it's nil ,but why?
this is the init method.
but it never call it ,it only call the layoutSubview method.
Consider this sort of pattern...
-(id)initWithFrame:(CGRect)frame {
if (self = [super initWithFrame:frame]) {
[self _setup];
}
return self;
}
-(id)initWithCoder:(NSCoder *)aCoder {
if (self = [super initWithCoder:aCoder]) {
[self _setup];
}
return self;
}
-(void)_setup {
blah;
blah;
blah;
}
Try to "know what is happening" but that will get you through if you're just getting started. Hope it helps
It is in the awakeFromNib: method. Override it in your implementation file like this:
- (void)awakeFromNib {
[super awakeFromNib];
// Initialization code
[self setupStuff];
}

objective C [self init] hierarchy for multilevel inheritance

I have class A which inherits class B. And want to achieve something like below. But the init methods get recursive call due to dynamic typecasting.
Is there any way to achieve such? Any suggestion? (without changing 'init's name in subclass?
#interface A : NSObject
#property NSData * data;
#end
#implementation A
- (id) init {
self = [super init];
/* want to do some default initialization here
for this class and all of its subclasses. */
// ... ...
return self;
}
/* This [self init] get recursed.
But how can I force this class and all of its subclass to call [self init] above,
not to call the subclass's init method. */
- (id) initWithData:(NSData *)d {
self = [self init];
self.data = d;
return self;
}
#end
#interface B : A
#end
#import "B.h"
#implementation B
- (id) init {
self = [super initWithData:nil];
// some subclass specific init code here ...
return
}
#end
Using B,
- (void) testInit{
B * b = [[B alloc] init];
}
You're calling [self init] in your implementation which is causing the recursion issue..
Implement this way :
- (id) init {
self = [super init];
//Basic empty init...
return self;
}
- (id) initWithData:(NSData *)d
{
self = [super init]; //<---- check this line.
if(self)
{
self.data = d;
}
return self;
}
//If you are looking to write some init code only 1 time the the following can work.....
-(void)oneTimeWrittenInitCode:(id)mySelf
{
//your init code which you wish to write one time goes here...
}
- (id) init {
self = [super init];
if(self)
{
[self oneTimeWrittenInitCode:self];
}
return self;
}
- (id) initWithData:(NSData *)d
{
self = [super init];
if(self)
{
[self oneTimeWrittenInitCode:self];
self.data = d;
}
return self;
}
Look up the "designated initializer" pattern. It describes how to arrange initializer methods and convenience constructors (a.k.a. factory methods) in a class hierarchy.
Here is an example of designated initilizer pattern mentioned above,
#import ”Person.h”
#implementation Person
-(id) initWithAge:(int)theAge AndHeight:(int)theHeight AndName:(NSString *)theName {
if (self = [super init]){
_age = theAge;
_height = thefleight;
_name = theName;
}
return self;
}
-(id) initwithAge:(int)theAge AndHeight:(int)theHeight {
return [self initWithAge:theAge AndHeight:theHeight AndName:nil];
}
-(id) initwithAge:(int)theAge {
return [self initWithAge:theAge AndHeight:0];
}
- (id)init {
return [self initwithAge:0];
}
#end
It should be:
- (instancetype) initWithData:(NSData *)d
{
if(self = [super init])
{
_data = d;
}
return self;
}

initWithFrame not executing in UIVIew

I have made a UIView subclass & want to execute a method on initWithFrame:, but this method is not being called.
When I call the method from initWithCoder:, which is executing, the code crashes showing this error:
Terminating app due to uncaught exception 'NSGenericException', reason: 'This coder requires that replaced objects be returned from initialization coder method:'
My code is:
-(void)initialize
{
//code
}
-(id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
[self initialize];
// Initialization code
}
return self;
}
- (id)initWithCoder:(NSCoder *)aCoder
{
self = [super initWithCoder:aCoder];
if(self)
{
[self initialize];
}
return self;
}
You're not returning self from your initWithCoder: method.
Maybe you specify this UIView inside IB or storyBoard so initWithCoder is called.
Delete initWithCoder and use awakeFromNib
- (void)awakeFromNib{
//custom init code
[self initialize];
}
Try this one.
- (id)initWithCoder:(NSCoder *)aCoder
{
self = [super initWithCoder:aCoder];
if(self)
{
}
return self;
}

Resources