Reputation: 14984
I've managed to setup a custom UIView class with a nib.
My .h looks like
@interface MyView : UIView <UITextFieldDelegate>
@property (nonatomic, weak) IBOutlet UITextField *textField;
@property (nonatomic, strong) MyView *topView;
And .m
@implementation MyView
NSString *_detail;
-(id)initWithCoder:(NSCoder *)aDecoder{
if ((self = [super initWithCoder:aDecoder])&&self.subviews.count==0){
MyView *v = [[[NSBundle mainBundle] loadNibNamed:@"MyView" owner:self options:nil] objectAtIndex:0];
self.textField = v.textField;
if (self.topView == nil)self.topView = self;
v.topView = self.topView;
[self addSubview:v];
}
return self;
}
-(NSString *)topDetail{
return _detail;
}
-(NSString *)detail{
return [self.topView topDetail];
}
-(void)setTopDetail:(NSString *)detail{
_detail = detail;
}
-(void)setDetail:(NSString *)detail{
[self.topView setTopDetail:detail];
}
- (BOOL)textFieldShouldReturn{
//here I show an UIAlertView using self.detail for the message
}
Note: The setup I have works exactly how I want it to.
The problem
What I would like to do is remove my manual detail
methods and turn NSString *_detail
into @property (...)NSString *detail
When I try it with the @property
, then within my ViewController
if i call
myView.detail = someString
, myView will be referring to the top most view. Then if textFieldShouldReturn
gets called because of user interaction, then it calls the nested MyView
s _detail
which has not been set.
What I want:
To not have to write extra code for access to _detail
regardless of where I'm accessing it from. I want to merely declare the property and go on with my usual coding.
Upvotes: 1
Views: 1008
Reputation: 14984
My xib contained one UIView (no controller). I had the UIView
set to MyView
for the class.
I changed the UIView
back to just UIView
then set File's Owner
to MyView
. This solved issues of recursion (which is why I had such a weird setup in the first place) and caused my variables and IBOutlets to be linked up properly.
Credit goes to How do I create a custom iOS view class and instantiate multiple copies of it (in IB)? and some of the comments which I missed the first couple times I read through it.
Upvotes: 0
Reputation: 10938
Your problem is that you're trying to keep the a class reference, topView
, with an object property.
In other words every objects' topView
is the object itself, which makes no sense.
Your definition should be:
@interface MyView : UIView <UITextFieldDelegate>
// Class "properties"
+ (instancetype)topview;
+ (void)setTopView:(UIView *)topView;
// Object properties
@property (nonatomic, weak) IBOutlet UITextField *textField;
@property (nonatomic, strong) NSString *detail;
Now you can keep track of the topView
:
static MyView * _topView;
@implementation MyView
+ (instancetype)topView {return _topView}; // You could also create one here lazily
+ (void)setTopView:(UIView *)topView { _topView = topView };
-(id)initWithCoder:(NSCoder *)aDecoder{
if ((self = [super initWithCoder:aDecoder])&&self.subviews.count==0){
JUITextFieldHint *v = [[[NSBundle mainBundle] loadNibNamed:@"JUITextFieldHint" owner:self options:nil] objectAtIndex:0];
self.textField = v.textField;
if ([MyView topView] == nil)[MyView setTopView:self];
v.topView = self.topView;
[self addSubview:v];
}
return self;
}
No more need for manual setters and getters. Now you can use your detail
property, either with anyInstance.detail
or [MyView topView].detail
, or even MyView.topView.detail
if you like dots like me ;)
You're init
method still looks weird but should work. Check Apples init
template.
Lastly, textField
can be weak as long as it has a superview, otherwise make it strong
.
Upvotes: 1