Call DataSource method in awakeFromNib - ios

So the question is like this:
I subclass 2 classes, which is UIView(name: Menu) and UIViewController(name: MainController). In Menu, i used xib file to create it layout. In MainController, i added Menu as subview like this and comform to protocol in Menu.
SliderMenu *sliderMenu = [[[NSBundle mainBundle] loadNibNamed:#"SliderMenu" owner:self options:nil] objectAtIndex:0];
sliderMenu.datasource = self;
sliderMenu.delegate = self;
[self.view addSubview:sliderMenu];
The layout works perfectly, there is no problem with it.
The problem is with DataSource. i call a datasource method in awakeFromNib
- (void)awakeFromNib {
// Alloc data
self.data = [[NSArray alloc] initWithArray:[self.datasource arrayOfData]];
}
and that never even get called. After trying and trying i found out that, sliderMenu.datasource = self;is run after awakeFromNib. Thats is why the datasource method in MainController is never get called.
Question:
How can i solve this problem?

If you put a breakpoint in -awakeFromNib method, you'll see that this method executes as it should.
The thing is, that this method called before datasource assignment, and at this moment your self.datasource is nil.
I suggest you to override the setter of the datasource property and initialize your data there, e.g.
- (void)setDatasource:(id<YourProtocol>)datasource
{
_datasource = datasource;
self.data = [[NSArray alloc] initWithArray:[datasource arrayOfData]];
}
OR
make a public method, say, prepare and do all your initialization there,
- (void)prepare
{
self.data = [[NSArray alloc] initWithArray:[self.datasource arrayOfData]];
}
and call this method after datasource assignment:
SliderMenu *sliderMenu = [[[NSBundle mainBundle] loadNibNamed:#"SliderMenu" owner:self options:nil] objectAtIndex:0];
sliderMenu.datasource = self;
sliderMenu.delegate = self;
[sliderMenu prepare];
[self.view addSubview:sliderMenu];

Related

UIView that loaded from nib files , can i set the owner to the view it self?

the most common method to init is
UIView *rootView = [[[NSBundle mainBundle] loadNibNamed:#"MyRootView" owner:self options:nil] objectAtIndex:0];
and in my case , self is refer to a view controller , but i have to set the owner to the view itself ,because there is many outlet between .m and .xib , how to do with this situations?
You should use a init method in your view.m class like:
- (id)initWithNibNamed:(NSString *)nibName{
NSArray *nibContents = [[NSBundle mainBundle] loadNibNamed:nibName owner:nil options:nil];
self = [nibContents lastObject];
if(self){
//do your code here
}
return self;
}
and call this method from viewcontroller. Connect view to view xib.
thanks stack overflow , there is already a perfect solution for this kind of problem .
https://github.com/PaulSolt/CompositeXib
the key is to call the loadNibNamed in the custom view 's implementation ,not in the controller that create the view.

iOS mutable array always null

heres my conundrum
i am try to put a table view above my view controller
the view loads and is added, the array that i am using for the tableview is always null however so the table is always empty!
here is my view header file with my tableview and mutable array properties
#interface IngredientsView : UIView <UITableViewDataSource,UITableViewDelegate>
- (id)initWithFrame:(CGRect)frame andIngredients:(NSMutableArray*)ingredientsArray;
- (id)initWithIngredients:(NSMutableArray*)ingredientsArray;
#property (weak, nonatomic) IBOutlet UITableView *notesTableView;
#property NSMutableArray* ingredients;
my custom init method takes in the array and sets it - here is my custom init
- (id)initWithIngredients:(NSMutableArray*)ingredientsArray;
{
self.ingredients = [[NSMutableArray alloc]init];
self.ingredients=ingredientsArray;
NSLog(#"hello from init %lu", (unsigned long)[self.ingredients count]);
if (self) {
self = [[[NSBundle mainBundle] loadNibNamed:[NSString stringWithFormat:#"%#", [self class]] owner:self options:nil] objectAtIndex:0];
UIImageView* view = [[UIImageView alloc]initWithImage:[UIImage imageNamed:#"ingredients background.png"]];
self.notesTableView.backgroundView=view;
self.backgroundColor = [UIColor colorWithRed:0/255.0f green:0/255.0f blue:0/255.0f alpha:0.6f];
self.notesTableView.dataSource = self;
self.notesTableView.delegate = self;
UIGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(close)];
[self addGestureRecognizer:tapGesture];
[self.notesTableView reloadData];
}
return self;
}
inside the init method the self.ingredients array will return a count (e.g. 6 objects) to NSlog
but in my delegate table view method numberOfSectionsFor:index path it always returns 0 as if the array is nil
i have tried
using a instance array instead
synthesising the array and setting it from my view controller
sticking the array on a singleton and grabbing the array from a singleton
all return 0 for number of sections ?
is the tableview nil?
i normally use table view controllers and don't have much experience using just tableviews is there something i have missed?
your setting self.ingredients=ingredientsArray; and then on the following line setting self to a nib that you your loading, overwriting self. Move the self.ingredients assignment to after you set self to the nib.
Which of your initializers are called? If you are being loaded from an xib file, certainly
-(id) initWithFrame:(CGRect)frame andIngredients:
is not called
- (id) initWithFrame: is the designated initializer for views. so it will be called when loading views from a nib file.
In any case , the first thing your initWith... code should do is:
self = [super initWithFrame: ... ]
if (self)
{
...
}
The MOST critical problem:
You are assigning self = [[[NSBundle mainBundle] loadNibNamed:[NSString stringWithFormat:#"%#", [self class]] owner:self options:nil] objectAtIndex:0];
You just blasted over self which is being initialized.
If you were wanting IngredientsView to be loaded from the XIB file, you might also consider implementing -(void) awakeFromNib {...} to set your properties, or set the properties in the - (self) InitWithFrame: .... after calling[super initWIthFrame:rect]`

Can't get UITextFieldDelegate to work

I write a custom view CustomViewA : UIView<UITextFieldDelegate>and implements the delegate's methods.
And in the CustomViewA's init I write:
- (id)initWithFrame:(CGRect)frame {
self = [[[NSBundle mainBundle] loadNibNamed:#"CustomViewA" owner:self options:nil] objectAtIndex:0];
if (self) {
//the txtfieldA is a IBOutlet property linked to the nib file.
self.txtfieldA.delegate = self; //not work
}
return self;
}
And in this xib file includes a UITextField control which I set its delegate in the init method.But when I run this and edit the textfield, the delegate's methods are not called.Can anyone tell me why? And how can I fix it??
To load a view which subclass an UIView from a xib file, you can do this way:
// Reusable method to load a class which subclass UIView from a xib.
+ (id)loadNibNamed:(NSString *)nibName ofClass:(Class)objClass andOwner:(id)owner {
if (nibName && objClass) {
NSArray *objects = [[NSBundle mainBundle] loadNibNamed:nibName owner:owner options:nil];
for (id currentObject in objects ){
if ([currentObject isKindOfClass:objClass])
return currentObject;
}
}
return nil;
}
Then add the view in your controller:
myCustomViewA = [self loadNibNamed:#"customviewA" ofClass:[CustomViewA class] andOwner:self];
myCustomViewA.delegate = self; // Or do this in the xib file
[self.view addSubview:myCustomViewA];
Ensure that that the UITextField is correctly wired to the IBOutlet of of CustomViewA.
Otherwise, attempting to set the delegate in init will do nothing,
//if self.myTextField is nil, then this does nothing
self.myTextField.delegate = self;
just simply do not use -(id)init if you init a view from xib files.
and set your UITextField's delegate method in - (void)awakeFromNib..

Accessing subviews delegate methods

My Views Hierarchy is next:
My root View Controller that contains custom view
My custom UIView that contain custom UITableView
My custom UITableView
And i want to use delegate methods of my custom UITableView, but i don't really know how to access it's delegates because UITableView is added in my custom UIView class. Please clear me up, i'm little confused about this question.
Here's my code:
Adding my custom UITableView to UIView(i'm using CollapseClick):
-(void) initMehod{
DetailsView *testView = [[[NSBundle mainBundle] loadNibNamed:#"DetailsView" owner:self options:nil] lastObject];
test1View = testView;
//collapse click init
CGRect viewRect = [test1View frame];
viewRect.origin.x = 10;
test1View.frame = viewRect;
[test1View setBackgroundColor:[UIColor magentaColor]];
self.myCollapseClick.CollapseClickDelegate = self;
[self.myCollapseClick reloadCollapseClick];
// If you want a cell open on load, run this method:
[self.myCollapseClick openCollapseClickCellAtIndex:0 animated:NO];
}
...
And i'm using PagedFlowView in my root View Controller to add CustomView:
- (UIView *)flowView:(PagedFlowView *)flowView cellForPageAtIndex:(NSInteger)index{
mainDetailV = (MainDetailView *)[flowView dequeueReusableCell];
if (!mainDetailV) {
mainDetailV = [[[NSBundle mainBundle] loadNibNamed:#"MainDetailView" owner:self options:nil] lastObject];
//mainDetailV.layer.cornerRadius = 6;
mainDetailV.layer.masksToBounds = YES;
}
[usedViewControllers insertObject:mainDetailV atIndex:index];
return mainDetailV;
}
Everything works perfectly, except i can't use my custom UITableView delegate (for example didSelectRowAtIndexPath: method).
EDIT: I have fixed my problem, PagedFlowView actually handles tag gesture recogniser and overrides my custom tableView delegate methods.
Similar question:
UITableView as a subview?
First of all your collapsable tableview abstracts tableview delegates (i.e its a wrapper).
It provides you with a method didClickCollapseClickCellAtIndex instead. Use that.
It seems to be that you have some problem in understanding delegation pattern.
Avoid breaking the cascading effect of delegation pattern. It makes debugging easy
and helps to understand the flow of the code. Below diagram might help you to understand what I mean
Implement you didSelectRowAtIndexPath in custom view instead of rootViewcontroller.
// This is your custom view
-(id)init{
----
self.myCollapseClick.CollapseClickDelegate = self;
----
}
//collapsable delegate
-(void)didClickCollapseClickCellAtIndex:(int)index isNowOpen:(BOOL)open {
// you need to create your own custom view delegate with mehthod didSelectIndex:index
[self.customViewDelegate didSelectIndex:index];
}
In your rootviewcontroller you need to do this
customView.customViewDelegate = self;
-(void)didSelectIndex:(int)index{
// do your stuff here
}

Change view properties after adding it as subview

I'm creating app where i'm using pagedFlowView. I have custom view (mainDetailV) with ImageView as background and label on top. I'm using PagedFlowView delegate method to init all the views in it:
- (UIView *)flowView:(PagedFlowView *)flowView cellForPageAtIndex:(NSInteger)index{
mainDetailV = (MainDetailView *)[flowView dequeueReusableCell];
if (!mainDetailV) {
mainDetailV = [[[NSBundle mainBundle] loadNibNamed:#"MainDetailView" owner:self options:nil] lastObject];
//mainDetailV.layer.cornerRadius = 6;
mainDetailV.layer.masksToBounds = YES;
}
return mainDetailV;
}
It's adding my view 5 times in pageFlowView.
I want to trigger some action, like changing alpha of label, on tapping the imageView, but i don't really know how to do this.
My main question is how can i change properties of this view after it's added to pagedViewController?
Similar question
Access properties of subview
What is the definition of mainDetailV? It seems very strange to have this set as an Ivar
You should create mainDetailV as a local var and store it's contents in a mutable array just before you return it's value. So:
- (UIView *)flowView:(PagedFlowView *)flowView cellForPageAtIndex:(NSInteger)index{
id mainDetailV = [flowView dequeueReusableCell];
if (!mainDetailV) {
mainDetailV = [[[NSBundle mainBundle] loadNibNamed:#"MainDetailView" owner:self options:nil] lastObject];
//mainDetailV.layer.cornerRadius = 6;
mainDetailV.layer.masksToBounds = YES;
}
[usedViewControllers insertObject:mainDetailV atIndex:index];
return mainDetailV;
}
where usedViewControllers is a NSMutableArray instance variable.
Then you can use the delegate method like so:
- (void)flowView:(PagedFlowView *)flowView didTapPageAtIndex:(NSInteger)index;
{
MainDetailView *view = (MainDetailView *)[usedViewControllers objectAtIndex:index];
}
(In addition to my comment)
I have looked into PagedFlowView delegate and there is a method
- (void)flowView:(PagedFlowView *)flowView didTapPageAtIndex:(NSInteger)index;
you can use the integer index to get the cell/page from the flow view that was tapped. If you have this one you can edit its properties.
Hope this helps.

Resources