i want to use UITableCustomCell in my application but i am invoking the custom cell from another class.
When i use UITableViewCell then i need to add these lines to call tableviewcells from another class
/*
SurahViewController *aBookDetail = [[SurahViewController alloc]
initWithNibName:#"SurahView" bundle:nil];
self.surahViewController = aBookDetail;
[self.navigationController pushViewController:surahViewController animated:YES];
[aBookDetail release];
*/
but when i use UITableViewCustomCell in my application and i want to invoke custom table view cell from another class then there is no idea of what code to use to call that UITableCustomCell from another class.
Thank you in advance.
I'm doing it with the following code:
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
[[NSBundle mainBundle] loadNibNamed:#"UILogbookTVCell" owner:self options:nil];
cell = tvCell;
tvCell = nil;
}
Note that tvCell is an UITableView IBOutlet. In the UILogbookTVCell.xib the File's Owner is the UITableViewController implementation, and the UITableViewCell element is connected to the tvCell IBOutlet. Therefore the NSBundle loadNibNamed sets the property tvCell, which can then be set to the local cell and cleared.
This is also the official variant as described in the Table View Programming Guide.
Related
This is very common question at SO though I have google and cross check my code few times but I am not able to figure out the crash
*** -[MyCustomCell performSelector:withObject:withObject:]: message sent to deallocated instance 0x96f6980
I have a CustomCell named MyCustomCell with XIB where I have 3 buttons for Facebook,Twitter,LinkedIn. I gave them all IBAction in CustomCell class.
When I click on any of them I get this kind of crash.
I am using ARC.
In my ViewController class I have cellForRowAtIndexPath
{
static NSString *CellIdentifier = #"MyCustomCell";
MyCustomCell *cell = (MyCustomCell*)[myTableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil)
{
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:CellIdentifier owner:self options:nil];
cell = (MyCustomCell *)[nib objectAtIndex:1];
}
return cell;
}
MyCustomCell.m
- (IBAction)facebookPressed:(BaseButton *)sender {
}
- (IBAction)twitterPressed:(BaseButton *)sender {
}
- (IBAction)linkedInPressed:(BaseButton *)sender {
}
I made this mistake just today! :) all you gotta do is replace the 2 lines
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:#"NameOfCustomCellNibFile" owner:self options:nil];
cell = [nib objectAtIndex:1];
You have to load the loadNibNamed: with the .xib file's name. I also thought it was with the identifier, but that is regarding the name that is referenced into the cell instead of the nib for the cell.
Hope this helps!
you can also code for Custom cell like this way. At nib of custom cell drag one UIButton and set it's tag in Xib. then use bellow Method:-
UIButton *btnMulSelected;
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString *CellIdentifier =[NSString stringWithFormat:#"%d_%d",indexPath.section,indexPath.row];
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil)
{
[[NSBundle mainBundle]loadNibNamed:#"cell_custome_iphones" owner:self options:nil];
cell = self.tblCell;
self.tblCell = nil;
btnMulSelected =(UIButton*)[cell.contentView viewWithTag:2];
[btnMulSelected addTarget:self action:#selector(MyButtonAction:) forControlEvents:UIControlEventTouchUpInside];
}
return cell;
}
Do not connect IBAction from Nib. just connect Custom-cell IBOutlate or put Unique UIButton tag from nib.
You've to keep the class name of cell and the XIB names same.
Keep the owner nil generally.
Also, if there is only 1 view ( i.e. 1 UITableViewCell in your case ), then this view is available at index 0 instead of index 1.
Inside the XIB file, make sure you link the button to your view itself, i.e. to IBOutlet or IBAction.
The linked buttons must be already added to your view, not floating outside in XIB. Otherwise they will instantiate and come at other indices of the loaded array. If you don't want a certain button for some time, then just keep it hidden.
So the code can be as below:
NSArray *views = [[NSBundle mainBundle] loadNibNamed:#"MyCustomCell" owner: nil options:nil];
MyCustomCell *cell = (MyCustomCell*)[views objectAtIndex:0];
Further make sure you do the following for creating XIB
Ok, then here goes the other portion simple process:
Create a MyCustomCell class derived from UITableViewCell class.
Create a separate .xib file with same name as MyCustomCell.xib.
Open .xib and delete the existing view in it. drag and drop a new
UITableViewCell from the objects of editor.
See the image to change the class name of the UITableViewCell in XIB to your class name.
Now the objectAtIndex 0 will return MyCustomCell.
Add all your buttons and other views in this UITableViewCell of your XIB.
Currently I have the following method, but it doesn't quite work...
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *MyIdentifier = #"cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:MyIdentifier];
if (cell == nil) {
[[NSBundle mainBundle] loadNibNamed:#"TVCell" owner:self options:nil];
cell = tvCell;
self.tvCell = nil;
}
UILabel *label;
label = (UILabel *)[cell viewWithTag:5];
label.text = [NSString stringWithFormat:#"Hole #%d", indexPath.row];
return cell;
}
The table view gets created with no errors, but each individual cell contains nothing, but clearly the TVCell.xib has a label with a tag of 5. The only question I have is this. I don't quite understand these steps apple gives here...
Select File’s Owner in the nib document window, open the Identity pane of the inspector, and set the class of File’s Owner to your custom view controller class.
Connect the cell outlet of File’s Owner (now the placeholder instance of your custom subclass) to the table-view cell object in the nib-file document.
Here is where those steps are...
http://developer.apple.com/library/ios/#documentation/UserExperience/Conceptual/TableView_iPhone/TableViewCells/TableViewCells.html#//apple_ref/doc/uid/TP40007451-CH7
Can someone please explain those steps for a noob like me? I think that is what I messed up on, but I could have done anything wrong.
I don't think TcCell becomes a property of self. Try this instead when the cell queue is empty:
if (cell == nil) {
cell=[[NSBundle mainBundle] loadNibNamed:#"TVCell" owner:self options:nil];
}
It's kind of difficult to explain the steps that you said you don't understand in words. I would suggest looking for tutorials that have images or videos for that. (I did a quick search and there are lots available, but I didn't really want to choose one to direct you to without having read them more closely).
However, I prefer to create custom table view cells this way:
http://www.mobilesce.com/2011/12/27/the-best-way-to-do-custom-reusable-uitableviewcells/
It's slightly different from the way described in the apple docs, but I've seen a lot of people use it and I find it easier.
The NSBundle method loadNibNamed:owner:options: returns an NSArray containing the top level objects in your nib file. Try this:
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:MyIdentifier];
if (cell == nil) {
NSArray *nibArray = [[NSBundle mainBundle] loadNibNamed:#"TVCell" owner:self options:nil];
cell = [nibArray objectAtIndex:0];
}
I was trying to create a custom UITableViewCell in Interface Builder and kept setting the File's Owner and Custom Class of the actual UITableViewCell to my new custom UITableViewCell Class. I would hook up the IBOutlets from the File's Owner and get errors when it came to:
TVCell *cell = (TVCell *) [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
NSArray *topLevelObjects = [[NSBundle mainBundle] loadNibNamed:#"TVCell" owner:nil options:nil];
for(id currentObject in topLevelObjects)
{
if([currentObject isKindOfClass:[TVCell class]])
{
cell = (TVCell *)currentObject;
break;
}
}
Finally I realized you have to hook up the IBOutlets from the UITableViewCell Object, and not the File's Owner. Why is this?
Thanks
The File's Owner is a placeholder object for the object that will eventually load the NIB. It's a way for objects outside the NIB to refer to objects inside the NIB. In your case, you're trying to create the table view cell from the NIB, so you'll need some other object to be the owner. The table view cell can't both be outside and inside the NIB.
In this line of your code:
NSArray *topLevelObjects = [[NSBundle mainBundle] loadNibNamed:#"TVCell"
owner:nil
options:nil];
You get to specify an object for the File's Owner placeholder in Interface Builder to resolve to. I'm guessing your code is in a class like 'MyTableViewController'. If it is, you could pass 'self' for the owner parameter to -[NSBundle loadNibNamed:owner:]. If you did that, you could have outlets on the MyTableViewController class that would be useful for loading this NIB. Specifically, you could use them to avoid the for loop you have. You'd do that like this:
Add a 'loadedTableViewCell' outlet to MyTableViewController
In the table cell nib, set the file's owner to MyTableViewController.
Make a connection for 'loadedTableViewCell' from the file's owner to the table view cell.
Then change your code to be similar to this:
TVCell *cell = (TVCell *) [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
[[NSBundle mainBundle] loadNibNamed:#"TVCell" owner:self options:nil];
cell = [self loadedTableViewCell];
[self setLoadedTableViewCell:nil];
}
It's because you're pulling objects out of the nib, not using the whole nib, like you would if you were loading a controller. That's what the for (id currentObject in topLevelObjects) does.
I have Custom uitableviewcell: ScrollViewCell
I want to know what the difference is between the following code
static NSString *CellIdentifier = #"ScrollViewCell";
ScrollViewCell *cell = (ScrollViewCell*)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
//***** WHAT IS THE DIFFERENCE BETWEEN THIS CODE AND..
NSArray *xibObj = [[NSBundle mainBundle] loadNibNamed:#"ScrollViewCell" owner:nil options:nil];
for(id currentObj in xibObj){
if ([currentObj isKindOfClass:[ScrollViewCell class]]) {
cell = (ScrollViewCell *) currentObj;
}
}
//***** ..THIS CODE
cell = [[ScrollViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
Which one should I use and why?
The first example will load a cell from a .xib file in your application's bundle. Each cell can handle it's own code, and behaves a lot like a UIViewController. This approach can get complicated when you try and load data from an array. You have to pass the object you're getting data out of to the cell, and have a very clear design before you start coding.
The other method allocates an empty instance of the UITableViewCell class as normal. This approach is typically used for programmatic configuration of the cells. You'll probably see this one in most places.
Good luck,
Aurum Aquila
I'm using indexPath.row do determine in which row of my tableview I do something. The title of my cells is containing a number which should be 1 in the first row and 18 in the last row, so I have 18 rows. This works for the first 11 rows, but after that, I have numbers in the title which seem to be generated randomly! Sometimes 16, then 5, then 18, then 12... and so on.
What's the problem with it/why does the indexPath.row variable behave like that?
My cellForRowAtIndexPath method:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *MyIdentifier = #"MyIdentifier";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:MyIdentifier];
if (cell == nil) {
[[NSBundle mainBundle] loadNibNamed:#"myCell" owner:self options:nil];
cell = cell0;
self.cell0 = nil;
}
UILabel *label;
label = (UILabel *)[cell viewWithTag:1];
label.text = [NSString stringWithFormat:#"Cell %d", indexPath.row];
return cell;
}
Any more suggestions on how to solve the problem? I didn't get it working until now...
// Update with more code:
Here is how I declare the cell. It is in an XIB file (template "empty XIB") in which I just put the cell from the library in IB.
#interface myViewController : UITableViewController {
UITableViewCell *cell0;
}
#property (nonatomic, retain) IBOutlet UITableViewCell *cell0;
Then, at the top of the myViewController.m file:
#synthesize cell0;
My cellForRowAtIndexPath method is already posted above. It is equal to the cellForRowAtIndexPath method in the SDK documentation, and in Apple's example, it seems to work.
What are you trying to accomplish with cell0?
cell = cell0;
self.cell0 = nil;
It looks like you're creating a new cell, but somehow deciding to use an old one. The real culprit looks like the code that is loading the cell actually getting assigned anywhere.
Try just this instead:
if (cell == nil) {
cell = [[NSBundle mainBundle] loadNibNamed:#"myCell" owner:self options:nil];
}
Or perhaps:
if (cell == nil)
{
// TODO: try to avoid view controller
UIViewController *vc = [[UIViewController alloc] initWithNibName:#"IndividualContractWithResult" bundle:nil];
cell = (IndividualContractWithResult_Cell *) vc.view;
[vc release];
}
To would be easier to answer if you give the code where you create cells for your table view. It looks that there's a problem with reusing cells - you reuse previously created cells without setting a new value to it.
It sounds like you are not re-using cells but creating new ones when there are cells available. Look at the sample code for dequeueReusableCellWithIdentifier.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"MyCell"];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:#"MyCell"] autorelease];
}
cell.text = <your code here>;
return cell;
}
It would seem that you're incorrectly accessing a property here:
cell = cell0;
self.cell0 = nil;
Assuming that you have an instance variable named cell0, by setting it to nil, you may be releasing it before you're ready to use it.
The proper way to do this is:
cell = self.cell0;
self.cell0 = nil;
This way, if cell0 is declared as retain, you'll automatically get an autoreleased cell0 back, whereas if you reference cell0 directly (no self.), you'll get an unretained reference, which will disappear when self.cell0 = nil is called.
The advantage of using a nib-based cell here is that you can use outlets, rather than tags, to identify subviews. You've done the heavy lifting already, you might want to just add an outlet and subclass UITableViewCell to get access to the label.
You will need to retain and autorelease cell0, otherwise when you set self.cell0 = nil, then cell0 has no known references.
cell = [[cell0 retain] autorelease];
self.cell0 = nil;
You can also do this:
cell = self.cell0;
self.cell0 = nil;
.. Since any retain properties should implement their getters with the retain/autorelease pattern.