I'm sure there is a simple solution and I have looked around and cannot find any help. I'm trying to pass data from a UITableview to a subview. I do not want to use a segue as I want the xib file to appear on the same viewcontroller with the required data. The NSLog outputs as expected but doesn't pass to the string in the "nowplayingnib" view.
ViewController.m
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
SongInfo *song = songsArray[indexPath.row];
NowPlayingNib *nowplayingnib = (NowPlayingNib *)[NowPlayingNib viewFromNib];
[self.view addSubview:nowplayingnib];
nowplayingnib.videoId = song.videoId;
NSLog(#"%#", song.videoId);
}
UPDATE
NowPlayingNib.h
#interface NowPlayingNib : UIView
#property (strong, nonatomic) NSString *videoId;
#property (strong, nonatomic) NSString *title;
+(id)viewFromNib;
#end
NowPlaying.m
#implementation NowPlayingNib
#synthesize videoId;
-(void)awakeFromNib{
NSLog(#"video id inside nib = %#", self.videoId);
}
+(id)viewFromNib{
ViewController *songinfo = [[[NSBundle mainBundle] loadNibNamed:#"NowPlayingNib" owner:self options:NULL]lastObject];
return songinfo;
}
Your output NSLog(#"video id inside nib = %#", self.videoId);
is in the awakeFromNib-method, but you are only assigning the value to videoId after the nib has been loaded and added to the superview?
what's the type of nowplayingnib.videoId ?
make it #property (nonatomic,strong) and check again
rewrite init method like:
+(id)viewFromNib{
ViewController *songinfo = [[[NSBundle mainBundle] loadNibNamed:NSStringFromClass([self class]) owner:nil options:NULL]lastObject];
return songinfo;
}
Related
In my app I have a custom Google Map pin marker designed in a Nib file. Part of the pin marker will display an estimated arrival time.
Here is how I am loading the Nib, and attempting to set a custom time:
self.markerPinFromNib = [[[NSBundle mainBundle] loadNibNamed:#"PinWithTimeView" owner:self options:nil] firstObject];
self.markerPinFromNib.estTime.text = #"20";
When I run this, I get an error:
-[UIView estTime]: unrecognized selector sent to instance
PinWithTimeView.h
#import <UIKit/UIKit.h>
#interface PinWithTimeView : UIView
#property (nonatomic, weak) IBOutlet UIImageView *rotateCircle;
#property (nonatomic, strong) IBOutlet UILabel *estTime;
#end
Can someone point out what I'm doing wrong?
In your PinWithTimeView.h
#interface PinWithTimeView : UIView
#property (nonatomic, weak) IBOutlet UIImageView *rotateCircle;
#property (nonatomic, weak) IBOutlet UILabel *estTime;
-(id)initWithEstTime:(NSString*)time;
#end
In your PinWithTimeView.m
-(id)initWithEstTime:(NSString*)time{
self = [super init];
if (self) {
self = [[[NSBundle mainBundle] loadNibNamed:#"PinWithTimeView" owner:self options:nil] objectAtIndex:0];
self.estTime.text = time;
}
return self;
}
In your controller
self.markerPinFromNib = [[PinWithTimeView alloc]initWithEstTime:#"20"];
You should convert the instance from nib to PinWithTimeView in force. Like this:
((PinWithTimeView *)self.markerPinFromNib).estTime.text = #"20";
Because loadNibNamed:owner:options: will return a array include UIView instances.
I've read quite a few tutorials online about how to create a custom cell subclass, but I'm still a little confused. When I try to follow the instructions found in this question, I end up with errors that the tableView is not a valid property for the object of ViewController.
I've created a new subclass of UITableViewCell, called CustomBookClass. I've hooked up the properties with my CustomBookClass.h file.
#import <UIKit/UIKit.h>
#interface CustomBookCell : UITableViewCell
#property (weak, nonatomic) IBOutlet UIImageView *bookImage;
#property (weak, nonatomic) IBOutlet UILabel *bookTitle;
#property (weak, nonatomic) IBOutlet UILabel *dateAdded;
#end
I then go into my ViewController.m file to edit the viewDidLoad method.
- (void)viewDidLoad
{
[super viewDidLoad];
[self.tableView.delegate = self];
[self.tableView.dataSource=self];
[self.tableView registerClass:[CustomBookCell class]forCellReuseIdentifier:#"Custom
Cell"];
}
I get an error on the tableView, saying the property doesn't exist, even though in the ViewController.h file, I'm including the table view.
#import <UIKit/UIKit.h>
#interface ViewController : UIViewController <UITableViewDelegate,
UITableViewDataSource>
#end
I'm sure I'm missing something really obvious here, as this is my first time trying this. Can anyone help me out? Thanks!
UIViewController does not have that property. Even if you assign the Delegate and DataSource protocols to it. There are a couple of things you can do however.
Link the table view to the ViewController yourself. That means, create a property/outlet called tableView.
Inherit from UITableViewController instead of UIViewController.
Both should work.
Edit: Oh and the lines:
[self.tableView.delegate = self];
[self.tableView.dataSource=self];
don't make sense. They should be either:
self.tableView.delegate = self; and self.tableView.dataSource = self;
Or [self.tableView setDelegate:self]; and [self.tableView setDataSource:self]
with 1 being preferred. (Edit: option #2 was actually incorrect code, my bad.)
No need to set delegate and datasource in TableViewCell class
simple make a property and synthesize your table view item
#property (weak, nonatomic) IBOutlet UIImageView *bookImage;
#property (weak, nonatomic) IBOutlet UILabel *bookTitle;
#property (weak, nonatomic) IBOutlet UILabel *dateAdded;
now import your cell class in your tableView controller class
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *simpleTableIdentifier = #"SimpleTableCell";
SimpleTableCell *cell = (SimpleTableCell *)[tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier];
if (cell == nil)
{
//If you are using xib for representing your UI then add a nib file.
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:#"SimpleTableCell" owner:self options:nil];
cell = [nib objectAtIndex:0];
}
cell.bookTitle.text = [tableData objectAtIndex:indexPath.row];
cell.bookImage.image = [UIImage imageNamed:[thumbnails objectAtIndex:indexPath.row]];
cell.dateAdded.text = [prepTime objectAtIndex:indexPath.row];
return cell;
}
for more detail check this link
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 MyViews _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.
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.
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.
I have 2 table cells, based on what i have selected in my first cell, i have to refresh the second cell, when i click the second cell a container view with a picker is changed from hidden to unhidden state.
When I press the cell I have a method which gets called where after i get the new data I reload my picker, but that line of code doesn't get called, my picker isn't refreshed:
-(void)reloadData:(NSUInteger) path{
//NSUInteger path = (NSUInteger)self.parentVC.pozOras;
NSString *parcareFile = [[NSBundle mainBundle] pathForResource:#"Parcare"
ofType:#"plist"];
self.fisier = [NSArray arrayWithContentsOfFile:parcareFile];
////Log(#"reloadData:%#",self.fisier);
NSDictionary *infoOras = [self.fisier objectAtIndex:path];
// NSLog(#"reloadData:%#",infoOras);
NSLog(#"reloadData:%d",(NSInteger)path);
NSArray *zones = [infoOras valueForKey:#"Zone"];
self.zone = [zones valueForKey:#"name"];
NSLog(#"reloadData:%#",self.zone);
self.price = [zones valueForKey:#"price"];
NSLog(#"reloadData:%#",self.price);
self.time = [zones valueForKey:#"durationminutes"];
NSLog(#"reloadData:%#",self.time);
[self.listaCuZone reloadAllComponents];
}
All the data from the Output of NSLog is what is should be in the picker.
I have the property of the UIPickerView in the header file, everything seems to be in place. I really don't know why it doesn't get called.
#interface PickerZone : UIViewController<UIPickerViewDataSource,UIPickerViewDelegate>
#property (nonatomic, assign) FirstViewController *parentVC;
#property NSInteger zona;
#property NSUInteger path;
#property NSMutableArray *fisier;
#property NSMutableArray *zone, *price, *time;
#property (strong, nonatomic) IBOutlet UIPickerView *listaCuZone;
- (IBAction)doneButton:(id)sender;
- (void)reloadData:(NSUInteger)path;
#end
Here is where i call the method from:
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
if(indexPath.section == 0){
[self.listaZone viewForBaselineLayout].hidden = YES;
[self.listaOrase viewForBaselineLayout].hidden = NO;
}
else
{
PickerZone *pickerZone = [[PickerZone alloc]init];
[pickerZone reloadData:(NSUInteger)self.pozOras];
[pickerZone.listaCuZone reloadAllComponents];
[self.listaOrase viewForBaselineLayout].hidden = YES;
[self.listaZone viewForBaselineLayout].hidden = NO;
}
}
As you can see, i also try to reload the components here.
I have the delegate and the datasource also linked to the vc.
If i should post some more code please let me know, i really want to fix this.
Here is a screenshot of the storyboard: https://www.dropbox.com/s/4nkpz55zlcffh9w/Screenshot%202014-02-16%2019.31.24.png
Ok, so I have tried this a lot of different ways...
At the moment I have placed the UINavigationBar with the IB. Then declared it with IBOutlet.
From there I can't seem to change the title no matter what i try. Even just in ViewDidLoad.
Also, I dont need to assign the delegate of the navbar do i?
Here is my code:
#import <UIKit/UIKit.h>
#interface ViewController : UIViewController < UITableViewDataSource, UITableViewDelegate>
{
NSArray *myArrayOne;
NSArray *myArrayTwo;
UITextView *myTextView;
UINavigationBar *myNavBar;
}
#property (nonatomic, retain) NSArray *myArrayOne;
#property (nonatomic, retain) NSArray *myArrayTwo;
#property (nonatomic, retain) IBOutlet UITextView *myTextView;
#property (nonatomic, retain) IBOutlet UINavigationBar *myNavBar;
#end
and:
#import "ViewController.h"
#interface ViewController ()
#end
#implementation ViewController
//Synthesising anything with a property call in the .h file.
#synthesize myArrayOne;
#synthesize myArrayTwo;
#synthesize myTextView;
#synthesize myNavBar;
- (void)viewDidLoad
{
//declaring and instantiating datapaths and also
// reading into arrays from plist.
NSString *datapath1 = [[NSBundle mainBundle] pathForResource:#"myListOne" ofType:#"plist"];
NSString *datapath2 = [[NSBundle mainBundle] pathForResource:#"myListTwo" ofType:#"plist"];
myArrayOne = [[NSArray alloc] initWithContentsOfFile:datapath1];
myArrayTwo = [[NSArray alloc] initWithContentsOfFile:datapath2];
self.navigationItem.title = #"Hi";
[super viewDidLoad];
}
#pragma mark - TableView Delegate stuff
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
//myNavBar.title = [myArrayOne objectAtIndex:indexPath.row];
[tableView deselectRowAtIndexPath:indexPath animated:YES];
}
#pragma mark - TableView Datasource stuff
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
//returns amount of items inside myArrayOne as amount of rows
return [myArrayOne count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *myCell = nil;
myCell = [tableView dequeueReusableCellWithIdentifier:#"myReuseCell"];
if (myCell == nil)
{
myCell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"myReuseCell"];
}
myCell.textLabel.text = [myArrayOne objectAtIndex:indexPath.row];
return myCell;
}
#end
the actual code to change the title is just one way i have tried...
Any other way? And do I need to link the navigationbar in the IB with anything?
If you have a navigation bar without a navigation controller, you have to give it a stack (in your case, a stack of one) navigation items.
In viewDidLoad of your view controller, add your view controller's navigation item to the stack:
self.myNavBar.items = #[self.navigationItem];
Now you can set the title like so:
self.navigationItem.title = #"Hello";
and it will appear in your navigation bar.
The solution above by jrturton works fine UNLESS you also have a UIBarButtonItem (e.g. a "Done" button) in the UINavigationBar. In that case, the proposed solution causes the UIBarButtonItem to disappear.
Here's how to do it in a way that lets you change the UINavigationBar title but also preserve the UIBarButtonItem:
Add IBOutlet UINavigationItem *myNavigationItem; to your code.
In IB, in the outline view (not the storyboard view), right click the containing UIViewController and drag to the UINavigationItem that was automatically created by IB inside the UINavigationBar and connect to myNavigationItem.
Back in your code, add self.myNavigationItem.title = #"Hello";
I think you need to have a navigationController instead why don't you check this link:
create navigation bar for tableView programmatically in objective-C
and if you already have a navigation controller in your app delegate, then you should remove the IBoutlet you've created then use:
self.navigationItem.title = #"Hi";
for this will be referring the navigationController in your app delegate.