Design for custom tableviewcell button action
-
I'd like to add a custom button to my own custom tableview subclass
that will perform an action on the tableviewcontroller class. This is
pretty much identical to the way accessoryviews call a method on the
tableviewdelegate when it is tapped. The difference is it will be my
own button placed where I choose in the cell. The problem I'm having
is figuring out how to propagate this to the tableviewcontroller. The
UITableViewCell class does not hold a reference back to the tableview
or controller, so I'm a little confused on the best way to set up this
behavior. Can anyone offer some insight on the correct way to get a
button tap in a cell to call a method on the tableviewcontroller? One
that does not have bad coupling in its design?
Thanks,
Bryan -
Set your controller as the buttons taget:
– addTarget:action:forControlEvents:
UIControlEventTouchUpInside
atze
Am 25.06.2009 um 08:30 schrieb Bryan Hansen:
> I'd like to add a custom button to my own custom tableview subclass
> that will perform an action on the tableviewcontroller class. This
> is pretty much identical to the way accessoryviews call a method on
> the tableviewdelegate when it is tapped. The difference is it will
> be my own button placed where I choose in the cell. The problem I'm
> having is figuring out how to propagate this to the
> tableviewcontroller. The UITableViewCell class does not hold a
> reference back to the tableview or controller, so I'm a little
> confused on the best way to set up this behavior. Can anyone offer
> some insight on the correct way to get a button tap in a cell to
> call a method on the tableviewcontroller? One that does not have bad
> coupling in its design?
>
> Thanks,
> Bryan
-
Hi Bryan,
I had exactly the same problem and here's how I solved it. I have a
custom table view cell in a separate nib file whose File Owner's class
is the table view controller class. I then have an IB action defined
in the table view controller class and I link the button in the cell
nib to the action in the table view controller by linking the button
to the cell's File Owner's action instead. Of course, I still need to
attach the table view controller object to each actual cell's File
Owner, which I do here:
- (UITableViewCell*) tableView: (UITableView*) table_view
cellForRowAtIndexPath: (NSIndexPath*) index_path
{
static NSString* cellID = @"cellID";
CustomCell* cell = (CustomCell*) [table_view
dequeueReusableCellWithIdentifier: cellID];
if (cell == nil)
{
NSArray* nib = [[NSBundle mainBundle]
loadNibNamed: @"CellNibName" owner: self options: nil];
cell = (CustomCell*) [nib objectAtIndex: 0];
// other one-time cell configuration stuff here
}
// per-cell configuration stuff here
}
Note the two key steps:
1) the File Owner proxy object in the custom cell's nib file must have
its class set to your table view controller class.
2) you must pass 'self' as the owner in the -
loadNibNamed:owner:options: call.
This way, when the button is tapped, the action in the table view
controller is triggered. Now, presumably, you know which cell is
currently selected (you probably keep track of that in your table view
controller class), so you always know which cell the button action
came from.
Alternatively, you can set the button's tag to an index that depends
on the cell's index path. If your table has only one section, then
button.tag = [index_path row];
would do be sufficient. You should set the tag inside the if (cell ==
nil) block above, assuming that you expose the button as a cell
property and assuming that you're not adding or deleting cells. If you
do add or delete cells, you should set the button tag *outside* the if
(cell == nil) block. Either way, you can identify which row (ie, which
cell) is responsible for triggering the action by looking at the
action's sender's tag.
Wagner
On Jun 25, 2009, at 8:30 AM, Bryan Hansen wrote:
> I'd like to add a custom button to my own custom tableview subclass
> that will perform an action on the tableviewcontroller class. This
> is pretty much identical to the way accessoryviews call a method on
> the tableviewdelegate when it is tapped. The difference is it will
> be my own button placed where I choose in the cell. The problem I'm
> having is figuring out how to propagate this to the
> tableviewcontroller. The UITableViewCell class does not hold a
> reference back to the tableview or controller, so I'm a little
> confused on the best way to set up this behavior. Can anyone offer
> some insight on the correct way to get a button tap in a cell to
> call a method on the tableviewcontroller? One that does not have bad
> coupling in its design?
>
> Thanks,
> Bryan
-
Am 25.06.2009 um 10:16 schrieb WT:
> I had exactly the same problem and here's how I solved it.
Why didn’t you put the cell into the controllers nib?
Make an outlet in your controller to reach the cell and just return it
when you need it?
The second nib seems to much work. And you get a speed bump by loading
it.
> - (UITableViewCell*) tableView: (UITableView*) table_view
> cellForRowAtIndexPath: (NSIndexPath*) index_path
> {
> static NSString* cellID = @"cellID";
>
> CustomCell* cell = (CustomCell*) [table_view
> dequeueReusableCellWithIdentifier: cellID];
>
> if (cell == nil)
> {
> cell = customCellOutlet;
>
> // other one-time cell configuration stuff here
> }
>
> // per-cell configuration stuff here
> }
atze -
On Jun 25, 2009, at 10:26 AM, Alexander Spohr wrote:
> Am 25.06.2009 um 10:16 schrieb WT:
>
>> I had exactly the same problem and here's how I solved it.
>
> Why didn’t you put the cell into the controllers nib?
> Make an outlet in your controller to reach the cell and just return
> it when you need it?
>
> The second nib seems to much work. And you get a speed bump by
> loading it.
>
>> - (UITableViewCell*) tableView: (UITableView*) table_view
>> cellForRowAtIndexPath: (NSIndexPath*) index_path
>> {
>> static NSString* cellID = @"cellID";
>>
>> CustomCell* cell = (CustomCell*) [table_view
>> dequeueReusableCellWithIdentifier: cellID];
>>
>> if (cell == nil)
>> {
>> cell = customCellOutlet;
>>
>> // other one-time cell configuration stuff here
>> }
>>
>> // per-cell configuration stuff here
>> }
Because -tableView:cellForRowAtIndexPath: needs to return a different
cell object for each visible row. Your code above returns always the
same object, the one table view cell archived in the nib, which means
that changing the data in one cell would change the data in all
visible cells, and all visible cells would have the same data all the
time.
Wagner -
Am 25.06.2009 um 10:54 schrieb WT:
> On Jun 25, 2009, at 10:26 AM, Alexander Spohr wrote:
>
>> Why didn’t you put the cell into the controllers nib?
>> Make an outlet in your controller to reach the cell and just return
>> it when you need it?
>
> Because -tableView:cellForRowAtIndexPath: needs to return a
> different cell object for each visible row. Your code above returns
> always the same object, the one table view cell archived in the nib,
> which means that changing the data in one cell would change the data
> in all visible cells, and all visible cells would have the same data
> all the time.
Of course, you are right. I forgot that the OP wanted something like
an accessory which needs to be repetitive.
atze -
On Jun 25, 2009, at 11:46 AM, Alexander Spohr wrote:
> Am 25.06.2009 um 10:54 schrieb WT:
>
>> On Jun 25, 2009, at 10:26 AM, Alexander Spohr wrote:
>>
>>> Why didn’t you put the cell into the controllers nib?
>>> Make an outlet in your controller to reach the cell and just
>>> return it when you need it?
>>
>> Because -tableView:cellForRowAtIndexPath: needs to return a
>> different cell object for each visible row. Your code above returns
>> always the same object, the one table view cell archived in the
>> nib, which means that changing the data in one cell would change
>> the data in all visible cells, and all visible cells would have the
>> same data all the time.
>
> Of course, you are right. I forgot that the OP wanted something like
> an accessory which needs to be repetitive.
>
> atze
Even with a custom cell with no extra controls, you'd need to return a
different cell object for each visible row. Try this and see what
happens:
- (NSInteger) tableView: (UITableView*) table_view
numberOfRowsInSection: (NSInteger) section
{
return 10;
}
- (UITableViewCell*) tableView: (UITableView*) table_view
cellForRowAtIndexPath: (NSIndexPath*) index_path
{
NSInteger row = [index_path row];
static NSString* cellID = @"cellID";
UITableViewCell* cell = nil;
cell = [table_view dequeueReusableCellWithIdentifier: cellID];
if (cell == nil)
{
cell = customCell;
}
if (row % 2 == 0)
{
cell.contentView.backgroundColor = [UIColor blueColor];
}
else
{
cell.contentView.backgroundColor = [UIColor redColor];
}
return cell;
}
You will NOT see a table with alternating colors for its cells. I had
thought that you'd see all cells with the same color, but in fact I
was wrong about that. What you do see is that only ONE cell has its
background colored. And it makes perfect sense, since cells are views
and the ONE custom cell is repeatedly added as a subview to the table
view "content" area for each row, but only the last one "sticks"
because, again, you only have one cell object.
Wagner -
Am 25.06.2009 um 12:20 schrieb WT:
> On Jun 25, 2009, at 11:46 AM, Alexander Spohr wrote:
>
>> Of course, you are right. I forgot that the OP wanted something
>> like an accessory which needs to be repetitive.
>
> Even with a custom cell with no extra controls, you'd need to return
> a different cell object for each visible row.
That’s what I meant by "repetitive" ;)
I have some tables (for setup purposes) that use specialized cells in
only one row.
atze -
On Jun 25, 2009, at 12:36 PM, Alexander Spohr wrote:
> Am 25.06.2009 um 12:20 schrieb WT:
>
>> On Jun 25, 2009, at 11:46 AM, Alexander Spohr wrote:
>>
>>> Of course, you are right. I forgot that the OP wanted something
>>> like an accessory which needs to be repetitive.
>>
>> Even with a custom cell with no extra controls, you'd need to
>> return a different cell object for each visible row.
>
> That’s what I meant by "repetitive" ;)
> I have some tables (for setup purposes) that use specialized cells
> in only one row.
>
> atze
>
Ok, fair enough. My apologies for misunderstanding what you meant.
Wagner -
On Jun 24, 2009, at 11:30 PM, Bryan Hansen wrote:
> I'd like to add a custom button to my own custom tableview subclass
> that will perform an action on the tableviewcontroller class. This
> is pretty much identical to the way accessoryviews call a method on
> the tableviewdelegate when it is tapped. The difference is it will
> be my own button placed where I choose in the cell. The problem I'm
> having is figuring out how to propagate this to the
> tableviewcontroller. The UITableViewCell class does not hold a
> reference back to the tableview or controller, so I'm a little
> confused on the best way to set up this behavior. Can anyone offer
> some insight on the correct way to get a button tap in a cell to
> call a method on the tableviewcontroller? One that does not have bad
> coupling in its design?
>
Since this doesn't seem to have been fully addressed yet, and
particularly given that there are errors and an omission in one of the
responses:
There are two possible scenarios, for "static" or "replicated" content.
Static content
--------------
If you have a table view whose contents are "static" -- that is, you
have a small fixed set of unique cells are simply using the table view
for layout -- then it is reasonable to configure the individual cells,
including your button (and perhaps to make things easiest, the table
view itself), in a nib file. Broadly speaking the technique is then
as follows.
The class of the File's Owner should be your table view controller
class.
In your table view controller class, you declare outlets for the
various cells.
In the nib file, you connect the outlets to the cells (and if you
choose to put the table view in the nib file, connect the table view
outlet to the table view), and connect the button's action to the
File's Owner.
If you choose to put the table view in the nib file, you initialise
the table view controller using initWithNibName:bundle: and you're
pretty much done. In your tableView:cellForRowAtIndexPath: method you
check for the section/row and return the appropriate cell (configured
if necessary):
// Simplified code example
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath {
if (indexPath.row == 0) {
return cell0;
}
if (indexPath.row == 1) {
return cell1;
}
// (or use a case statement) etc. -- configuring cells where
appropriate.
If you don't put the table view in the same nib file and don't
initialise the table view controller using initWithNibName:bundle:,
then you load the cell's nib files in tableView:cellForRowAtIndexPath:
// Simplified code example
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath {
if (indexPath.row == 0) {
if (cell0 == nil) {
[[NSBundle mainBundle] loadNibNamed:@"MyCell" owner:self
options:nil];
}
return cell0;
}
// etc. -- configuring cells where appropriate.
Replicated content
------------------
If you replicate a cell within a table view, then (assuming you want
to use a nib file) the cell must go in a separate nib file so that you
can load it an arbitrary number of times, as discussed here: <https://devforums.apple.com/thread/3469?start=0&tstart=0>
To summarise the general approach, though, with a particular
implementation:
In your table view controller class, declare an outlet for the custom
cell and an action method for the button:
@property (nonatomic, assign) IBOutlet <#Your table view cell class#>
*<#cell outlet property#>;
- (IBAction)<#button action#>:(UIButton *)sender;
In your table view cell class, declare an outlet for the button (and
any other UI elements as appropriate):
@property (nonatomic, retain) IBOutlet UIButton *<#button property#>;
In the cell's nib file:
The class of the File's Owner should be your table view controller
class.
Set an identifier for the cell.
Connect the appropriate outlet from File's Owner to the cell
Connect the button's action to the File's Owner
Connect the cell's button outlet to the button
In your table view controller subclass, then implement the
tableView:cellForRowAtIndexPath: method along the following lines:
// Simplified code example
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = @"<#your cell's idenitifier#>";
<#Your table view cell class#> *cell = (<#Your table view cell
class#> *)
[tableView
dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
[[NSBundle mainBundle] loadNibNamed:@"<#Your nib file name#>"
owner:self options:nil];
cell = <#cell outlet property#>;
self.<#cell outlet property#> = nil;
}
cell.<#button property#>.tag = indexPath.row;
// implementation continues...
In your implementation of the action method, you can ask the button
for its tag (which will indicate the row with which it's associated).
- (IBAction)<#button action#>:(UIButton *)sender {
NSInteger row = sender.tag;
For an example that illustrates several aspects of this approach, see:
<http://developer.apple.com/iphone/library/samplecode/TaggedLocations/index.
html>
On Jun 25, 2009, at 1:16 AM, WT wrote:
> I have a custom table view cell in a separate nib file whose FileThere are errors and an omission in this description:
> Owner's class is the table view controller class.
> [...]
> static NSString* cellID = @"cellID";Note that you must specify the same identifier for the cell in the nib
>
file.
> NSArray* nib = [[NSBundle mainBundle]
> loadNibNamed: @"CellNibName" owner: self options: nil];
>
> cell = (CustomCell*) [nib objectAtIndex: 0];
>
In general, the appropriate way to refer to an object in the nib file
is using an outlet.
See above and <https://devforums.apple.com/thread/3469?
start=0&tstart=0> for a discussion of the technique.
> 2) you must pass 'self' as the owner in the -There is no guarantee that if a button is tapped the corresponding row
> loadNibNamed:owner:options: call.
> This way, when the button is tapped, the action in the table view
> controller is triggered. Now, presumably, you know which cell is
> currently selected (you probably keep track of that in your table
> view controller class), so you always know which cell the button
> action came from.
>
is selected (in fact it typically won't be). Moreover, *in general*,
selections in a table view should be temporary, so you should actually
not be keeping track of the current selection (see the iPhone UI
Guidelines for details).
> Alternatively, you can set the button's tag to an index that depends
> on the cell's index path. If your table has only one section, then
> button.tag = [index_path row];
> would do be sufficient. You should set the tag inside the if (cell
> == nil) block above, assuming that you expose the button as a cell
> property and assuming that you're not adding or deleting cells. If
> you do add or delete cells, you should set the button tag *outside*
> the if (cell == nil) block. Either way, you can identify which row
> (ie, which cell) is responsible for triggering the action by looking
> at the action's sender's tag.
>
Whether or not cells are added or deleted is not relevant.
If (as will typically be the case) cells may be *reused*, then you
should set the tag for the cell *outside* of the (cell == nil) block
since the identifier should be updated each time the cell is reclaimed
to display a different row.
mmalc -
On Jun 26, 2009, at 9:08 PM, mmalc Crawford wrote:
> if (cell == nil) {
> [[NSBundle mainBundle] loadNibNamed:@"<#Your nib file name#>"
> owner:self options:nil];
> cell = <#cell outlet property#>;
> self.<#cell outlet property#> = nil;
> }
Please pardon my noobness, but could you expand a little on how this
works? I'm assuming that the first line somehow assigns the <#cell
outlet property#>, since I don't see how else this could work, but I
sure don't see how that actually happens. It certainly looks like a
alloc/assign/release pattern, but I feel like there should be some
more code.
Thanks,
Brian -
On Jun 26, 2009, at 7:20 PM, Brian Slick wrote:
> Please pardon my noobness, but could you expand a little on how this
> works? I'm assuming that the first line somehow assigns the <#cell
> outlet property#>, since I don't see how else this could work, but I
> sure don't see how that actually happens. It certainly looks like a
> alloc/assign/release pattern, but I feel like there should be some
> more code.
From the set-up:
In the cell's nib file:
The class of the File's Owner should be your table view controller
class.
Set an identifier for the cell.
** Connect the appropriate outlet from File's Owner to the cell **
When the nib file is loaded, the cell property is set to point to the
newly-loaded cell.
(It's not related to memory management.)
mmalc -
One more question about this approach...
On Jun 26, 2009, at 9:08 PM, mmalc Crawford wrote:
> In the cell's nib file:
> The class of the File's Owner should be your table view controller
> class.
> Set an identifier for the cell.
> Connect the appropriate outlet from File's Owner to the cell
> Connect the button's action to the File's Owner
> Connect the cell's button outlet to the button
Does the first line mean that I cannot reuse the XIB-based cells in
different view controllers?
I currently have several custom cells (code only) that are used in 3
different view controllers. The approach I am using is a combination
of the Apple-provided sample 'TouchCells' and this post: http://weblog.bignerdranch.com/?p=56
It looks like this:
if (cell == nil)
{
cell = (MyCustomCell *)[[[MyCustomCell alloc]
initWithFrame:CGRectZero
reuseIdentifier:MyCustomCellIdentifier] autorelease];
[[cell checkButton] addTarget:self
action:@selector(buttonPressed:)
forControlEvents:UIControlEventTouchUpInside];
}
...where checkButton is a UIButton property of the custom cell. (and
I am aware that I need to update my initWithFrame: method). This
exact code works equally well in all 3 view controllers.
This is serving me well so far, though now that I am past my "I avoid
IB for iPhone development" phase, I'm interested in reworking my cells
around IB. But, if that means I have to have 3 copies of the same
file just so that File's Owner can be different, I'm losing interest.
Is there a way to use this technique and share the cells with multiple
view controllers?
This might be more of a general question regarding XIB reuse. At the
moment, I have a handful of XIB files for view controllers that are
identical except for File's Owner. It would be nice to get away with
using a single file.
Thanks,
Brian -
On Jun 30, 2009, at 4:36 PM, Brian Slick wrote:
> Does the first line mean that I cannot reuse the XIB-based cells inNo. As long as the view controllers all provide the same API (the
> different view controllers?
>
actions and outlets) you use in the nib file, then the actual class
doesn't really matter. (Obviously this puts a little more
responsibility on you to ensure that all your classes are kept in sync.)
(It might actually be useful if Interface Builder allowed you to set a
protocol rather than a class for the identity of an object:
<rdar://problem/7022113> Allow object identity to be set to a protocol
)
mmalc -
Well, at first I really liked this technique, and it seems simple
enough. I restructured my program to use it, and in the simulator all
went well. Then I uploaded to the phone (1st-gen) and saw absolutely
horrid scrolling performance. I fired up the CA tool, and saw numbers
that were well under 10 FPS, usually around 4.
I did make a slight adjustment to the technique - most significantly
the omitting of the identifier in the XIB file, because I have a few
different display options that hide various aspects of my cell -
because I wasn't getting the flexibility I wanted. In order to
determine if my changes were causing a problem, I built the
TaggedLocations example, and also ran it on the phone with the CA
tool. Similar numbers, similarly horrid scrolling performance.
Rebooting the phone didn't seem to make a difference for either program.
I flipped on the "Color Blended Layers" toggle for both programs, to
see if there were any key differences. My UIButton image has a
transparent background, so that lit up, but that has been the case all
along, and I had decent scrolling performance before. The primary
event name label in the TaggedLocations example lit up. 1 field in
each case, although in terms of number of pixels the TaggedLocations
program is even worse than mine.
So, if TaggedLocations was flying while mine was sucking, I'd probably
concede that what I was doing was wrong (and would probably need more
custom cells). But since neither one is performing very well, and I
can't find any significant differences between them, I'm thinking
there is either a flaw with this approach, or my trusty 1st-gen just
isn't bringing enough horsepower to handle it.
For now, I think I'll just go back to code-only cells, although if
there are any thoughts about what the problem is and/or what I can do
about it, I'd be interested in hearing them.
Brian
On Jun 26, 2009, at 9:08 PM, mmalc Crawford wrote:
> Replicated content> >
> ------------------
> If you replicate a cell within a table view, then (assuming you want
> to use a nib file) the cell must go in a separate nib file so that
> you can load it an arbitrary number of times, as discussed here: <https://devforums.apple.com/thread/3469?start=0&tstart=0
>> >
> To summarise the general approach, though, with a particular
> implementation:
>
> In your table view controller class, declare an outlet for the
> custom cell and an action method for the button:
> @property (nonatomic, assign) IBOutlet <#Your table view cell class#>
> *<#cell outlet property#>;
> - (IBAction)<#button action#>:(UIButton *)sender;
>
> In your table view cell class, declare an outlet for the button (and
> any other UI elements as appropriate):
> @property (nonatomic, retain) IBOutlet UIButton *<#button property#>;
>
> In the cell's nib file:
> The class of the File's Owner should be your table view controller
> class.
> Set an identifier for the cell.
> Connect the appropriate outlet from File's Owner to the cell
> Connect the button's action to the File's Owner
> Connect the cell's button outlet to the button
>
>
> In your table view controller subclass, then implement the
> tableView:cellForRowAtIndexPath: method along the following lines:
>
> // Simplified code example
> - (UITableViewCell *)tableView:(UITableView *)tableView
> cellForRowAtIndexPath:(NSIndexPath *)indexPath {
>
> static NSString *CellIdentifier = @"<#your cell's idenitifier#>";
>
> <#Your table view cell class#> *cell = (<#Your table view cell
> class#> *)
> [tableView
> dequeueReusableCellWithIdentifier:CellIdentifier];
>
> if (cell == nil) {
> [[NSBundle mainBundle] loadNibNamed:@"<#Your nib file name#>"
> owner:self options:nil];
> cell = <#cell outlet property#>;
> self.<#cell outlet property#> = nil;
> }
>
> cell.<#button property#>.tag = indexPath.row;
>
> // implementation continues...
>
>
> In your implementation of the action method, you can ask the button
> for its tag (which will indicate the row with which it's associated).
>
> - (IBAction)<#button action#>:(UIButton *)sender {
>
> NSInteger row = sender.tag;
>
>
> For an example that illustrates several aspects of this approach, see:
> <http://developer.apple.com/iphone/library/samplecode/TaggedLocations/index.
html
-
On Jul 3, 2009, at 11:54 AM, Brian Slick wrote:
> So, if TaggedLocations was flying while mine was sucking, I'dThe only time you should see a performance hit with this approach is
> probably concede that what I was doing was wrong (and would probably
> need more custom cells). But since neither one is performing very
> well, and I can't find any significant differences between them, I'm
> thinking there is either a flaw with this approach, or my trusty 1st-
> gen just isn't bringing enough horsepower to handle it.
>
when the cells are first loaded; once they're loaded (and cached),
performance should be identical whether you code the cell
programmatically or use a nib file. *Without looking at any
performance metrics* (I don't have a device to hand), I'd *guess* the
issue is likely to be with transparency. Try switching off
transparency wherever you can find it and see if that helps.
If you can exactly recreate your hand-coded cell in IB, it would be
interesting to see what the performance comparison is like.
> I did make a slight adjustment to the technique - most significantly
> the omitting of the identifier in the XIB file,
>
This is actually a very significant factor.
If you haven't set an identifier, it's not clear how you're retrieving
cached cells in tableView:cellForRowAtIndexPath:?
I assume you have a test along the lines of:
UITableViewCell *cell = [tableView
dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = ...
Could you check whether you're creating a new cell each time?
All this aside, please file a performance bug against the
TaggedLocations sample.
mmalc -
On Jul 3, 2009, at 4:39 PM, mmalc Crawford wrote:
> On Jul 3, 2009, at 11:54 AM, Brian Slick wrote:
>
>> I did make a slight adjustment to the technique - most
>> significantly the omitting of the identifier in the XIB file,
>
> This is actually a very significant factor.
> If you haven't set an identifier, it's not clear how you're
> retrieving cached cells in tableView:cellForRowAtIndexPath:?
>
> I assume you have a test along the lines of:
>
> UITableViewCell *cell = [tableView
> dequeueReusableCellWithIdentifier:CellIdentifier];
> if (cell == nil) {
> cell = ...
>
> Could you check whether you're creating a new cell each time?
That's impressive; good call. It was indeed creating a new cell each
time. And now that I take a second look at the code, I'm pretty sure
I see why. The XIB-loading command itself doesn't actually have the
identifier as a parameter, and is thus totally dependent on that info
being in the XIB. Therefore, the cell never gets queued. My initial
thought was that omitting it would make it generic, but I now see the
flaw in that thinking. Simply declaring the identifier doesn't make
it get used anywhere. :p
Incidentally, that's what is wrong with TaggedLocations... it also
does not have the identifier in the XIB. I manually added it, then
retested, and saw dramatically better performance (for my own program,
too).
So now I either need to figure out how to make my scenarios all work
with a single identifier, or I may just go ahead with the code-only
cell I just built in response to the performance issue. If would be
nice if there was some kind of queueWithReuseIdentifier: method for
these XIB cases. (This is what I'm trying to do: http://bit.ly/l55eH )
> All this aside, please file a performance bug against the
> TaggedLocations sample.
Done, although I'm not sure if I did so correctly. Thank you for your
help.
Brian -
On Jul 3, 2009, at 2:45 PM, Brian Slick wrote:
> So now I either need to figure out how to make my scenarios all workOh, you can have as many identifiers as you want.
> with a single identifier, or I may just go ahead with the code-only
> cell I just built in response to the performance issue. If would be
> nice if there was some kind of queueWithReuseIdentifier: method for
> these XIB cases.
>
For a nib-based approach, simply have as many nib files as you want --
where each nib file has a single cell but a different identifier --
and you probably(*) have an outlet for each type.
// Caveat: Typed in Mail
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath {
if (condition1) {
static NSString *CellType1Identifier = @"CellType1Identifier";
CellType1 *cell = (CellType1 *)[tableView
dequeueReusableCellWithIdentifier:CellType1Identifier];
if (cell == nil) {
[[NSBundle mainBundle] loadNibNamed:@"CellType1" owner:self
options:nil];
cell = cellType1;
self. cellType1 = nil;
// configure cell ...
return cell;
}
if (condition2) {
static NSString *CellType12dentifier = @"CellType12dentifier";
CellType1 *cell = (CellType1 *)[tableView
dequeueReusableCellWithIdentifier:CellType2Identifier];
if (cell == nil) {
[[NSBundle mainBundle] loadNibNamed:@"CellType2" owner:self
options:nil];
cell = cellType2;
self. cellType2 = nil;
// configure cell ...
return cell;
}
// ...
(*) You wouldn't actually *need* a different outlet for each type,
since the outlet is used only very briefly for each load, and each
load happens sequentially, but you may prefer to identify each type
nevertheless.
> Incidentally, that's what is wrong with TaggedLocations... it also
> does not have the identifier in the XIB. I manually added it, then
> retested, and saw dramatically better performance (for my own
> program, too).
> [...]
>> All this aside, please file a performance bug against the
>> TaggedLocations sample.
> Done, although I'm not sure if I did so correctly. Thank you for
> your help.
>
Ah, thanks.
If you could send the bug number, that would be useful.
mmalc



