UITableViewCell - registerNib subclass not finding nib as subview - objective-c

In the viewDidLoad in my UITableView I am calling:
[self registerNib:[UINib nibWithNibName:#"MyCell" bundle:nil] forCellReuseIdentifier:#"MyCellRI"];
Then in the cellForRowAtIndexPath I have the following:
MyCell *cell = [tableView dequeueReusableCellWithIdentifier:#"MyCellRI"];
[cell setup:[items objectAtIndex:indexPath.row]];
Inside the setup method I have a look on [self subviews] to go through the subviews and assign content based on key/value but in this loop I find UITableViewCellContentView's but I do not see the my custom view defined in the NIB.
In the NIB I have assigned Files Owner & The custom class of my cell. The cell is showing I just can't find the NIB view in the subviews.
Please advise.
James

Iterating through subviews is hard work) Try to avoid it. it is not very good practice because it is not reliable. For instance if you decided to change your custom cell UI you will have to change method where you're iterating through subviews.
Try to do following:
Let's say that there is custom cell with UIImage and 3 strings (e.g. person's name, age and cell phone number)
Implement 3 functions in your custom cell to set this values as follows:
MyCustomCell.h
... .h file standart code and then at the end ...
#propert(nonatomic, strong) IBOutlet UIImageView *myImage;
#propert(nonatomic, strong) IBOutlet UILabel *myFirstLabel;
#propert(nonatomic, strong) IBOutlet UILabel *mySecondLabel;
#propert(nonatomic, strong) IBOutlet UILabel *myThirdLabel;
- (void)setUIimage:(UIImage *)_image;
- (void)setFirstString:(NSString *)_string;
- (void)setSecondString:(NSString *)_string;
- (void)setThirdString:(NSString *)_string;
MyCustomCell.m:
#synthesize myImageView, myFirstLabel, mySecondLabel, myThirdLabel;
- (void)setUIimage:(UIImage *)_image {
self.myImageView.image = _image;
}
- (void)setFirstString:(NSString *)_string {
self.myFirstLabel.text = _string;
}
- (void)setSecondString:(NSString *)_string {
self.mySecondLabel.text = _string;
}
- (void)setThirdString:(NSString *)_string {
self.myThirdLabel.text = _string;
}
and finaly in your tableView controller cellForRowAtIndexPath
[myCustomCell setUiImage:someImage];
[myCustomCell setFirstString:oneString];
[myCustomCell setSecondString:twoString];
[myCustomCell setThirdString:threeString];
Hope this approach will help you. Feel free to ask if you have some questions

Related

Passing Data Between View Controllers Not Working

I am attempting to pass the label for a given selected cell to a different view controller...
ListViewController.m
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
NSIndexPath *selectedIndexPath = [self.tableView indexPathForSelectedRow];
UITableViewCell *cell = [self.tableView cellForRowAtIndexPath:selectedIndexPath];
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"Storyboard" bundle: nil];
DetailViewController *viewController = [storyboard instantiateViewControllerWithIdentifier:#"DetailVC"];
viewController.venueName = cell.textLabel;
[self.navigationController pushViewController:viewController animated:YES];
}
Here is my DetailViewController:
.h
#interface DetailViewController : UIViewController {
IBOutlet UILabel *venueName;
}
#property (nonatomic, strong) IBOutlet UILabel *venueName;
venueName never gets the data. In my .m I also synthesize the venueName.
This happens because your UILabel outlet is not connected at the time you set a string for it. I recommend you to create a string property to store the value and, in viewDidLoad in DetailViewController, you set the string to venueName.
Cheers!!
You need to modify the below like that for setting and getting the text:-
viewController.venueName.text = cell.textLabel.text;
So venueName, which is a pointer to a label, is made to point to an existing label that's part of a table cell. This is obviously wrong -- you don't mean to use the actual label from the table cell, but rather the text stored in it. Both the other answers here are correct: you surely mean to assign the text property of one label to that of the other, and the label that outlet viewController.venueName is connected to hasn't been created at the time this code executes.
The immediate thing you should do to fix your code is to assign the data in question (i.e. cell.textLabel.text) to a string property in the destination view controller. Have the -viewDidLoad or -viewWillAppear method in that controller set the text property of the venueLabel label. Either of those methods will be called after the view hierarchy is instantiated.

UITextField inside UITableViewCell won't become first responder

I use a UITableViewController to display the details of KoreanFood. The first cell is a custom UITableViewCell (OverviewCell) with an Image and two UITextFields, which I created and layout in Storyboard (AutoLayout).
I subclassed UITableviewCell like this:
// OverviewCell.h
#interface OverviewCell : UITableViewCell
#property (strong, nonatomic) IBOutlet UITextField *englishTitleTF;
#property (strong, nonatomic) IBOutlet UITextField *koreanTitleTF;
#property (strong, nonatomic) IBOutlet UIImageView *myImageView;
#property (strong, nonatomic) UIImage *thumbnail;
My textfields in Storyboard are set to enabled/UserInteractionenabled and the delegate is my TVC. When I create the cells I also do this in code:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
if (indexPath.section == GENERAL_SECTION) {
static NSString *overviewCellID = #"overviewCell";
OverviewCell *overviewCell = [tableView dequeueReusableCellWithIdentifier:overviewCellID forIndexPath:indexPath];
overviewCell.englishTitleTF.text = self.generalInfo.titleEnglish;
overviewCell.koreanTitleTF.text = self.generalInfo.titleKorean;
overviewCell.englishTitleTF.enabled = YES;
overviewCell.koreanTitleTF.enabled = NO;
//BOOL test = [overviewCell.englishTitleTF becomeFirstResponder];
overviewCell.koreanTitleTF.delegate = self;
overviewCell.englishTitleTF.delegate = self;
UIImageView *imageView = [[UIImageView alloc] initWithImage:self.generalInfo.thumbnail];
overviewCell.myImageView = imageView;
overviewCell.myImageView.frame = CGRectMake(25, 25, 95, 95);
[overviewCell addSubview:overviewCell.myImageView];
return overviewCell;
}
The comment with the BOOL is NO, and I just don't know why... As I set the text and it's displayed correctly, I know the Outlets are set and the Cell isn't nil (I checked that).
Why does this not become first responder?
I also tried some suggestions inside the OverviewCell subclass like the hit test or implementing the setSelected: / setEditing: methods. But a becomeFirstResponder to the textField here doesn't change anything as well.
A view can't become first responder until it's been added to the responder chain, which happens automatically when the view gets added as a subview of a view that's in a window in the application object's windows list. In other words, your cell hasn't been added to the table view yet, so it's not connected to anything, and hence can't become first responder.
Try sending becomeFirstResponder from a method that gets called after the table view has finished loading its cells. And of course, don't do this:
overviewCell.koreanTitleTF.enabled = NO;

UILabel text not changing, however xx.title is working

I have two view controller. In first view controller I have list of names. When I click on that, I want the same name to be displayed in second view controller.
I have below code.
-(void) tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
// PropDetailViewController is second view controller
PropDetailViewController *prop = [self.storyboard instantiateViewControllerWithIdentifier:#"prop"];
ListOfProperty *propList = [propListFinal objectAtIndex:indexPath.row];
NSString *myText = [NSString stringWithFormat:#"%#", propList.addressOfFlat];
prop.detailLabel.text = myText;
prop.title = myText;
[self.navigationController pushViewController:prop animated:YES];
[tableView deselectRowAtIndexPath:indexPath animated:YES];
}
and in PropDetailViewController, I have #property (retain, nonatomic) IBOutlet UILabel *detailLabel;.
What I was expecting is when I click say Name 1, I will see Name 1 as text in UILabel and on the UINavigationBar too. However I only see Name 1 on navigation bar and not on UILabel.
It is not advisable to access an UIView item at that point in the program flow. When setting the value of prop.detailLabel.text the view may not have been loaded. When the view is loaded later then the UIView is updated with the default settings given in the XIB file in IB.
You should rather set an NSString property, lets say
#property (retain, nonatomic) NSString *propName;
assign it before pushing the view controller as you do. But use this property and not the UILable. And in PropDetailViewController in viewDidLoad do the following:
(void) viewDidLoad {
// call super viewDidLoad and all the works ...
self.detailLabel.text = propName;
}
Instead of viewDidLoad you could use viewWillAppear. Because viewDidLoad COULD be executed already when you assign the property's value.
If you want to be on the save side then invent a new init method where you hand over all the values that you want to be set upfront.
But I never did that in combination with storyboard (where you may use instantiate... rather than init...) and therefore I cannot give any advise out of the top of my head.
Another clean approach would be to stick with the propName property but to implement a custom setter -(void)setPropName:(NSString)propName; where you set the property (probably _propName if you autosynthesize) AND set the UILable text plus setting the UILable text within viewDidLoad.
Try this:
in .h
#property (retain, nonatomic) NSString *detailText;
in PropDetailViewController.m
Change line of code with
NSString *myText = [NSString stringWithFormat:#"%#", propList.addressOfFlat];
prop.detailText = myText;
prop.title = myText;
in ViewDidLoad:
[self.detailLabel setText:self.detailText];

Using a XIB file for custom Tableview Section Header

I wanted to use a xib file to customise a tableview section in xcode (objective C), and here ar my files:
SectionHeaderView.xib is a UIView with a UILabel
SectionHeaderView.m
#import "SectionHeaderView.h"
#implementation SectionHeaderView
#synthesize sectionHeader;
#end
SectionHeaderView.h
#import <UIKit/UIKit.h>
#interface SectionHeaderView : UIView
{
IBOutlet UILabel *sectionHeader;
}
#property (nonatomic, strong) IBOutlet UILabel *sectionHeader;
#end
and in my MasterViewController.m
#import "SectionHeaderView.h"
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {
SectionHeaderView *header = [[[NSBundle mainBundle] loadNibNamed:#"SectionHeaderView" owner:self options:nil] objectAtIndex:0];
return header;
}
It works ok till here, however as soon as I set XIB file owner's custom class to "SectionHeaderView" and connect the Label to "sectionHeader" I will get the error "NSUnknownKeyException". I wanted to connect these so I could change the label.text by the following code before returning the haeder:
header.sectionHeader.text = headerText;
I am using storyboard (xcode 4.5) for the MasterViewController.
Would appreciate any help
You can create a UITableViewCell subclass with an associated xib, and use it as the section header. In this example i will call it CustomTableViewHeaderCell.h/.m/.xib and show you how to change the text of a label inside this cell.
Create an outlet property in your CustomTableViewHeaderCell.h
#property (weak, nonatomic) IBOutlet UILabel *sectionHeaderLabel;
Add a UITableViewCell into the empty CustomTableViewHeaderCell.xib
and set the class of the element to CustomTableViewHeaderCell
from the Identity Inspector.
Set also the Identifier (attribute inspector of the cell) for example
CustomIdentifier.
Drag a label into the Content View and connect the outlet from the
CustomTableViewHeaderCell (Not the file owner!).
Then in each ViewController you want to use the table view section header cell:
1) Register your xib to reuse identifier (probably in viewDidLoad):
[_yourTableView registerNib:[UINib nibWithNibName:#"CustomTableViewHeader" bundle:nil] forCellReuseIdentifier:#"CustomIdentifier"];
2) Override viewForHeaderInSection to display your custom cell header view
-(UIView*)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section{
CustomTableViewHeaderCell * customHeaderCell = [tableView dequeueReusableCellWithIdentifier:#"CustomIdentifier"];
customHeaderCell.sectionHeaderLabel = #"What you want";
return customHeaderCell;
}
Try this: I have tested it in my app and its working:
NSArray *viewArray = [[NSBundle mainBundle] loadNibNamed:#"SectionHeaderview" owner:self options:nil];
UIView *view = [viewArray objectAtIndex:0];
UILabel *lblTitle = [view viewWithTag:101];
lblTitle.text = #"Text you want to set";
return view;
You can solve this issue by one of the following way:
1) you have derived SectionHeaderView from UIView. derive this class with UIViewController instead. This will resolve your issue.
2) Instead of using IBOutlet property, Set Tag of UILabel in view (say 101).
Discard SectionHeaderview class.
Keep SectionHeaderView.XIB, delete .m and .h files only.
use following code ins Viewforheader method of MasterViewController class:
{
UIViewController *vc=[[UIViewController alloc] initWithNibName:#"SectionHeaderview" bundle:nil]
UILable *lblTitle =[vc.view viewWithTag:101];
lblTitle.text =#"Text you want to set";
return vc.view;
}

Re-using IBOutlet programmatically

I have an UIView created in IB with some labels and custom colours and linked that as an IBOutlet so I could have access to it in my viewController.
#property (strong, nonatomic) IBOutlet UIView *tile;
although I would like to create more of this outlet within a loop:
- (void)viewDidLoad {
[super viewDidLoad];
int i = 0;
while (i <= 9) {
UIView *cTile = [self.tile copy];
[self.view addSubview:cTile];
i += 1;
}
}
So I'm trying to copy this tile outlet and then add the copied view to the main view.
Apparently this can't be done and returns an error.
Is it possible to achieve such behaviour and re-use/duplicate an IBOutlet?
I dont think what you want to do is possible as UIView doesn't conform to the NSCopying protocol.
Best bet would be to create your "tile" as a UIView subclass or crate a nib for it and then you can reload it as many times as you want.