My table view has inline cells adding.
I've got in cellForRowAtIndexPath:
VMEditableTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"EditableCell"];
cell.editableTF.font = [UIFont fontWithName:#"Helvetica" size:17.0];
cell.editableTF.delegate = self;
cell.editableTF.tag = indexPath.row;
[cell.editableTF setBorderStyle:UITextBorderStyleNone];
if ([self.extrasArray[indexPath.row] isEqual:#0]) { // recognise new added cell
self.extrasArray[indexPath.row] = #"";
[cell.editableTF becomeFirstResponder];
}
cell.editableTF.text = self.extrasArray[indexPath.row];
return cell;
When i start table view - inline adding works fine.
The problem starts when i use "clear whole list" button - which simply removes all objects from extrasArray.
When I add cell after clearing it's being dequeued improperly and the textfield doesnt respond to becomeFirstResponder.
(it's not nil, it calls textFieldShouldBeginEditing(always YES) but nothing more happens - no keyboard is showing up.
My last idea was to to override prepareForReuse method inside of Cell Implementation - but sadly neither setting editableTF to nil and reinitalizing it doesnt work.
How can I force cell to recreate itself instead of coping?
Try to create a cell like this
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:nil];
if (cell == nil)
{
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
// Set up the cell..
[self configureCell:cell atIndexPath:indexPath];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
}
'
So todays morning was very good for code soultions and finally I came up with one for this problem:
I got rid of storyboard for this cell and changed all pointers of custom cell to strong (so I own them).
Dequeque reusable cell was recreating UITextField from deleted rows making controller confused about ownership and becoming first responder.
be aware that creating them inside of cell init didn't do the trick.
TextField MUST be created and added as subview (also assigned to strong pointer so I get control over it later).
Here is some code:
VMEditableTableViewCell *cell = [[VMEditableTableViewCell alloc] init];
[cell setSelectionStyle:UITableViewCellSelectionStyleNone];
UIImage *bulletImage = [UIImage imageNamed:#"common_ico_dot.png"];
UIImageView *bulletImageView = [[UIImageView alloc] initWithFrame:CGRectMake(20,17,10, 10)];
bulletImageView.image = bulletImage;
UIImage *tickImage = [UIImage imageNamed:#"common_green_tick.png"];
UIImageView *tickImageView = [[UIImageView alloc] initWithFrame:CGRectMake(cell.bounds.size.width-30, 17, tickImage.size.width, tickImage.size.height)];
tickImageView.image = tickImage;
tickImageView.hidden = YES;
UITextField *textField = [[UITextField alloc] initWithFrame:CGRectMake(60, 10, 227, 30)];
textField.autocorrectionType = UITextAutocorrectionTypeNo;
textField.autocapitalizationType = UITextAutocapitalizationTypeNone;
textField.delegate = self;
textField.font = [UIFont fontWithName:#"Maven Pro" size:17.0];
textField.tag = indexPath.row;
[textField setBorderStyle:UITextBorderStyleNone];
[cell addSubview:bulletImageView];
cell.bulletImageView = bulletImageView;
[cell addSubview:tickImageView];
cell.tickImageView = tickImageView;
if (cell.editableTF == nil) {
[cell addSubview:textField];
cell.editableTF = textField;
}
Related
I have a tableview in which custom cells are created/reused for a lot of rows depending upon type of data encountered(i.e. For Date type , cell's textfield picks up the selected date from datePicker and for enum type , it picks the selected data from dropdown picker). Now there is a button at footer which needs to pick up the data from each cell and process it to display further view controller.
Since data in cells are displayed fine after selection(from datepicker or drop down or keypad) but how can we capture these data in footer button method.
Here is the code :-
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
// Return the number of rows in the section.
return [valueArray count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
TableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
if(cell == nil) {
cell = [[TableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];
}
NSString *values = [valueArray objectAtIndex:indexPath.row];
NSString *titles = [titleArray objectAtIndex:indexPath.row];
if([titles isEqualToString:#“enumType”]){
cell.headerInfo.hidden = true;
cell.valueObtained.hidden=true;
UITextField * scheduelText = [[UITextField alloc]initWithFrame:CGRectMake(20, 30, 130, 30)];
NSMutableArray* enumArray = [[NSMutableArray alloc] init];
[enumArray addObject:#"BUSINESS"];
[enumArray addObject:#"CUSTODIAL"];
[enumArray addObject:#"INDIVIDUAL"];
downPicker = [[DownPicker alloc] initWithTextField:scheduelText enumArray];
scheduelText.text = downPicker.text;
[cell addSubview:scheduelText];
}
else if([titles isEqualToString:#"DateType”]){
cell.headerInfo.hidden = true;
cell.valueObtained.hidden=true;
UITextField *dateText = [[UITextField alloc]initWithFrame:CGRectMake(20, 30, 130, 30)];
dateText.placeholder=#"Date";
dateText.inputView = self.datePicker;
UIToolbar *toolBar = [[UIToolbar alloc]initWithFrame:CGRectMake(0, 0, self.view.bounds.size.width, 44)];
UIBarButtonItem *doItem = [[UIBarButtonItem alloc]initWithBarButtonSystemItem:UIBarButtonSystemItemDone target:self action:#selector(dateDoneButton)];
[toolBar setItems:#[doItem]];
dateText.inputAccessoryView = toolBar;
[cell addSubview:dateText];
}
else if([titles isEqualToString:#“TextType”]){
cell.headerInfo.hidden = true;
cell.valueObtained.hidden=true;
UITextField * accountText = [[UITextField alloc]initWithFrame:CGRectMake(20, 30, 130, 30)];
accountText.returnKeyType = UIReturnKeyDone;
accountText.delegate = self;
accountText.placeholder=#"Account Name";
[accountText setTextColor:[UIColor blackColor]];
[accountText setBorderStyle:UITextBorderStyleNone];
[cell addSubview:accountText];
}
else{
cell.valueObtained.text = values;
cell.headerInfo.text = titles;
}
return cell;
}
- (void)submitButtonPressed:(id)sender
{
//Need to capture the cell data here ?
}
Please help out in this.
There seems to be a problem with your code:
[cell addSubview:scheduelText];
[cell addSubview:dateText];
[cell addSubview:accountText];
Everytime you dequeue the cell will add a new subview to the cell,but never removed.
In my suggestion,you'd better identifier 4 kind of cells with different identifiers,or removesubviews whenever dequeue the cell.
You can set tag for each of the textfield. and get UITextField from tag.
- (void)submitButtonPressed:(id)sender
{
UITableViewCell *cell =[tableview cellForRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:0]];
UITextField *txtField =[cell viewWithTag:TAG];
NSLog(#"%#",txtField.text);
}
Also, Please use custom cells for this.
Since you are using dynamic table view there is only an option. Delegate your controls and store their value on 'endEditing'. You can't use viewTag because view is going to be destroyed if is not visible on screen.
Another option is using static tableview and then you can create #IBOutlets for each control.
I am using table view using custom coding with tag method to save memory.
I was successful to show data in the view but the problem is if 10 cells are showing and then if I scroll down like for one cell then it should show 2-11 cell data but it switches to 1-10 again.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *cellIdentifier = #"cellID";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
UILabel *cellNAMElabl = nil;
UILabel *cellDetaillabl = nil;
UIImageView *imgView = nil;
if (cell == nil) {
cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:cellIdentifier];
cellNAMElabl = [[UILabel alloc] initWithFrame:CGRectMake(88, 10, 150, 20)];
[cellNAMElabl setTag:1];
cellNAMElabl.text = [name5 objectAtIndex:indexPath.row];
UIFont *myFont1 = [ UIFont fontWithName: #"Arial" size: 20.0 ];
cellNAMElabl.font = myFont1;
[cell.contentView addSubview:cellNAMElabl];
cellDetaillabl = [[UILabel alloc] initWithFrame:CGRectMake(88, 28, 150, 20)];
[cellDetaillabl setTag:2];
cellDetaillabl.text = [email5 objectAtIndex:indexPath.row];
UIFont *myFont = [ UIFont fontWithName: #"Arial" size: 13.0 ];
cellDetaillabl.font = myFont;
[cell.contentView addSubview:cellDetaillabl];
imgView=[[UIImageView alloc] initWithFrame:CGRectMake(25, 5, 52, 50)];
[imgView setTag:3];
imgView.image = [imagepath5 objectAtIndex:indexPath.row];
[cell.contentView addSubview:imgView];
}
cellNAMElabl = (UILabel *)[cell viewWithTag:1];
cellDetaillabl = (UILabel*)[cell viewWithTag:2];
imgView = (UIImageView*)[cell viewWithTag:3];
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
return cell;
}
You are not assigning new content to subviews, if they have been already created. After the case if(cell == nil), these you have just got references.
cellNAMElabl = (UILabel *)[cell viewWithTag:1];
cellDetaillabl = (UILabel*)[cell viewWithTag:2];
imgView = (UIImageView*)[cell viewWithTag:3];
Here when cell is not nil, you are just getting references to labels and imageview, but you are not setting new text and image from data source. Add following lines and remove them from the if (cell == nil) part:
cellNAMElabl.text = [name5 objectAtIndex:indexPath.row];
cellDetaillabl.text = [email5 objectAtIndex:indexPath.row];
imgView.image = [imagepath5 objectAtIndex:indexPath.row];
[cell.contentView addSubview:imgView];
The way this dequeueReusableCellWithIdentifier works: If iOS detects that a cell is not displayed anymore, then dequeueReusableCellWithIdentifier will return that cell. If there is no unused cell, it returns nil. So what you need to do:
If dequeueReusableCellWithIdentifier returns nil, then you create a new cell, and you do all the setup that is required for all cells with the same identifier. For example, add view tags like you did, set fonts, colors etc.
Then, whether you use a cell returned by dequeueReusableCellWithIdentifier or one that you just created yourself, you add all the information that is used for the specific section/row that you want to display. So if row 1, row2, and so on display different text, then you set the text here. That's what you didn't do, so when a cell was reused, you didn't set the new text for it.
So the idea is that all the work that is the same for all rows is only done once when a cell is created, and only as many cells are created as is needed to display them on the screen. The work that is different from row to row is done for each row, as it is needed.
If you set a breakpoint in the if cell == nil block its probably only being hit for the first set if your reuseID is correct. Thats why its never getting a chance to set any new data into the cell.
You should not look for a nil cell, rather use a correct reuseID and a prototype cell in IB that is set to a custom UITableViewCell subclass you create.
Its also good practice to implement prepareForReuse on custom cells, where you clear any cell data e.g. label.text = nil, imageview.image = nil
This way you dont get invalid data from previously dequeued cells. It might not solve the question directly, but it would have wiped the fixed data set in your if cell == nil block to help debug.
What you want to do is..
add/setup the tableViewCell UI if the cell is nil..
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *cellIdentifier = #"cellID";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:cellIdentifier];
UILabel *cellNAMElabl = [[UILabel alloc] initWithFrame:CGRectMake(88, 10, 150, 20)];
cellNAMElabl.tag = 1;
cellNAMElabl.font = [UIFont fontWithName: #"Arial" size: 20.0 ];
[cell.contentView addSubview:cellNAMElabl];
UILabel *cellDetaillabl = [[UILabel alloc] initWithFrame:CGRectMake(88, 28, 150, 20)];
cellDetaillabl.tag = 2;
cellDetaillabl.font = [UIFont fontWithName: #"Arial" size: 13.0 ];
[cell.contentView addSubview:cellDetaillabl];
UIImageView *imgView=[[UIImageView alloc] initWithFrame:CGRectMake(25, 5, 52, 50)];
imgView.tag = 3;
[cell.contentView addSubview:imgView];
}
//and just update your data if the cell is currently exist and not nil..
//you already called the view using tag so, you dont need those:
// UILabel *cellNAMElabl = nil;
// UILabel *cellDetaillabl = nil;
// UIImageView *imgView = nil;
((UILabel *)[cell viewWithTag:1]).text = [name5 objectAtIndex:indexPath.row]; // cellNAMElabl
((UILabel*)[cell viewWithTag:2]).text = [email5 objectAtIndex:indexPath.row]; // cellDetaillabl
((UIImageView*)[cell viewWithTag:3]).image = [imagepath5 objectAtIndex:indexPath.row]; // imgView
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
return cell;
}
hope this have help you, happy coding cheers!
CoreData returns BOOL value and according to the value I draw a UILabel on UITableViewCell accessoryView. The problem is that UILabel repeats itself also on the cells it shouldn't appear at all.
CGRect lblRect = CGRectMake(230, 7, 20, 20);
UILabel *lblEnabled = [[UILabel alloc] initWithFrame:lblRect];
lblEnabled.textColor=[UIColor whiteColor];
lblEnabled.textAlignment=NSTextAlignmentCenter;
[lblEnabled setFont:[UIFont fontWithName:#"Verdana" size:10.0]];
[lblEnabled setText:#"40"];
lblEnabled.backgroundColor= [UIColor colorWithPatternImage:[UIImage imageNamed:#"greenBg"]];
lblEnabled.layer.cornerRadius = 9.0;
lblEnabled.layer.masksToBounds = YES;
lblEnabled.tag = indexPath.row;
cell.accessoryView = lblEnabled;
[cell.contentView addSubview:lblEnabled];
So it appears sometimes on the cell where the BOOL value = NO; Your help is strongly appreciated.
EDIT: I draw these labels in cellForRowForIndexPath.
EDIT: I use storyboards, so I don't check if cell is nil.
-(UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *cellIdentifier=#"Cell";
UITableViewCell *cell =
[tableView dequeueReusableCellWithIdentifier:cellIdentifier];
/*
if(cell==nil)
{
cell=[[UITableViewCell alloc]initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:cellIdentifier];
tableView.rowHeight=57.0;
}*/
Coin *coin=[[self frcFromTV:tableView ] objectAtIndexPath:indexPath];
cell.textLabel.text=coin.coinNominal;
if(coin.comSubject.length>0)
{
cell.detailTextLabel.text=[NSString stringWithFormat:#"%#%# (%#) | %#",[self returnCatalogDefinition:coin.catalogIndex],coin.kmRef, coin.dates, coin.comSubject];
}
else
{
cell.detailTextLabel.text=[NSString stringWithFormat:#"%#%# | %#",[self returnCatalogDefinition:coin.catalogIndex],coin.kmRef,coin.dates];
}
if(coin.isCommemorative.boolValue)
{
// implement label
}
if(coin.listed.boolValue)
{
CGRect lblRect = CGRectMake(230, 7, 20, 20);
UILabel *lblEnabled = [[UILabel alloc] initWithFrame:lblRect];
lblEnabled.textColor=[UIColor whiteColor];
lblEnabled.textAlignment=NSTextAlignmentCenter;
[lblEnabled setFont:[UIFont fontWithName:#"Verdana" size:10.0]];
[lblEnabled setText:#"40"];
lblEnabled.backgroundColor= [UIColor colorWithPatternImage:[UIImage imageNamed:#"greenBg"]];
lblEnabled.layer.cornerRadius = 9.0;
lblEnabled.layer.masksToBounds = YES;
lblEnabled.tag = indexPath.row;
cell.accessoryView = lblEnabled;
[cell.contentView addSubview:lblEnabled];
}
return cell;
}
In code below you probably add your label but because those cells are reusable you should handle else statement (hiding label or whatever is appropriate)
if(coin.isCommemorative.boolValue)
{
// implement label
//remove from that part of the statement this line:
//[cell.contentView addSubview:lblEnabled];
} else {
cell.accessoryView = nil;
//hiding or modifying label for other cases
}
if you will not deal with that else statement the change you made in if will be applicable to more than one cell because of the reusing mechanism
As a "side advice" I would recommend you to subclass UITableViewCell and add the property you want (label) to encapsulate that and make only public method for showing or hiding that accessor.
EDIT:
if your flag for a change is not specifying to which cell it has to indicate (for example using indexPath) then the result is as your one.
This is quite global state if(coin.isCommemorative.boolValue) not indicating to which cell it counts try for example (for just learning purpose) add if(coin.isCommemorative.boolValue && indexPath.row%2==0) and see the result.
Are you reusing cells? If so, then you need to remove that cell from contentView inside prepareForReuse method.
I have a strange problem using the dequeueReusableCellWithIdentifier: method of UITableView. Not sure if I don't understand the method well enough or is it just plain weird. Here goes:
Im using a UITableView which presents some data to users, and inside my
- (UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath I use the dequeue method like so:
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"cell"];
if (!cell)
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"cell"];
Afterwards I add some subviews to the contentView property of the cell. When scrolling a bit further down on my table I see those previously added subviews i.e. the cell is not empty but filled with "old" data. If I don't dequeue, and just alloc-init a new one each time, the cells are empty but I do see a bit more memory consumption which is precisely what Im trying to bring down a little. I'm using ARC if that means anything here.
What or how should I tackle the problem? I have tried running a for loop through the subviews of the content view and [view removeFromSuperview] which does remove the previous views and brings down memory consumption a little. But is that really necessary? Or is there a better way?
EDIT here is some more code how I add subviews
cell.backgroundView = [[UIView alloc] initWithFrame:cell.frame];
cell.backgroundColor = kClearColor; //defined to [UIColor clearColor]
cell.selectionStyle = UITableViewCellSelectionStyleNone;
if (indexPath.row == 0)
{
UIImageView *shine = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 320, 50)];
shine.image = [UIImage imageNamed:#"top_shine_1"];
[cell.backgroundView addSubview:shine]; //its a gradient thats why its added to background
UILabel *appLabel = [[UILabel alloc] initWithFrame:CGRectMake(55, winSize.height * 0.027, 250, 33)];
appLabel.backgroundColor = kClearColor; //defined to clear color
appLabel.textColor = kWhiteColor; //defined to white color
appLabel.text = [viewOrder objectAtIndex:tableView.tag]; //just an array from where I get the required text
appLabel.font = kStandardFontOfSize(30); //defined to a specific font
[cell.contentView addSubview:appLabel];
UIButton *settingsButton = [UIButton buttonWithType:UIButtonTypeCustom];
settingsButton.frame = CGRectMake(10, winSize.height * 0.0377, 31, 21);
[settingsButton setImage:[UIImage imageNamed:#"settings_button"] forState:UIControlStateNormal];
[settingsButton addTarget:self action:#selector(settings:) forControlEvents:UIControlEventTouchUpInside];
[cell.contentView addSubview:settingsButton];
return cell; //here I just return it since this is all the config the first cell needs
}
NSString *app = [viewOrder objectAtIndex:tableView.tag];
NSArray *boxes = [[plist secondObjectForKey:#"order" parent:app] componentsSeparatedByString:#";"];
//Add necessary shines or create the last logotype cell - just some details and stuff, all are just images
if (indexPath.row == 1)
{
UIImageView *shine = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 320, 282.5)];
shine.image = [UIImage imageNamed:#"top_shine_2"];
[cell.backgroundView addSubview:shine];
}
else if (indexPath.row == 2)
{
UIImageView *shine = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, winSize.width, 150)];
shine.image = [UIImage imageNamed:#"main_shine"];
[cell.backgroundView addSubview:shine];
}
else if (indexPath.row == boxes.count + 1)
{
UIImageView *logo = [[UIImageView alloc] initWithFrame:CGRectMake(111.5, 25, 97, 20)];
logo.image = [UIImage imageNamed:#"cell_logo"];
[cell.backgroundView addSubview:logo];
return cell;
}
NSString *databox = [boxes objectAtIndex:indexPath.row - 1];
UIView *view; //Main subview to be added to the cell
/*
here I have a class that creates a view with a bunch of subviews added to that view, the view is then assigned to 'view'; kinda like
view = [someAssembler assembleViewWith:options.....]. all are basically UILabels or ImageViews added to the main view
*/
[cell.contentView addSubview:view]; //and here this 'main view' is added as a subview, this view is still visible after the cell has been dequeued and the shines are as well
return cell;
Before you start criticising why im not using a single UIColor for background and text color let me remind you that this is still in testing stage, it will be taken care of later.
[cell.backgroundView addSubview:shine]; these lines of code are the problem in your case.
You should create a complete reusable cell within the if (!cell) block and repopulate them each time cellForRow is being called. For every unique cell a unique reuse identifier should be used. For example, if you have multiple cells with differently laid out subviews, you should use different identifiers for them.
In your specific example cells must be created in the if (indexPath.row == 1) blocks.
static NSString *cellIdentifier = #"cell";
UITableViewCell *cell = nil;
if (indexPath.row == 0) {
cellIdentifier = #"topCell";
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
if (!cell) {
// create the cell and add the necessary subviews for indexPath row 0
}
return cell;
}
else if (indexPath.row == 1) {
}
//etc.
}
You'll have to create the "main subview" for each cell in the !cell block with this approach though, so you should probably look into subclassing a cell.
Into the cellForRowAtIndexPath: method of an UITableViewController class I am using the next code to show a cell that contains an UITextView.
Sometimes when I scroll the table that contains the cell and then I scroll the cell UITextView, it shows the cell text reprinted (as if there were two UITextView objects, instead of one, into the cell).
What can I do to solve this problem?
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
}
cell.contentView.bounds = CGRectMake(0, 0, cell.frame.size.width, cell.frame.size.height);
cell.selectionStyle = UITableViewCellSelectionStyleNone;
UITextView *textView = [[UITextView alloc] initWithFrame:cell.contentView.bounds];
textView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
textView.editable = NO;
textView.scrollEnabled = YES;
textView.backgroundColor = [UIColor clearColor];
textView.font = [UIFont fontWithName:#"Helvetica" size:14.0];
textView.text = self.description;
[cell.contentView addSubview:textView];
[textView release];
UITableView reuses its cells to increase scrolling performance. Whenever a cell is being reused, you are adding a new text view to the cell (although one is already there).
You should move the creation of the text view (and adding it to the cell) into the if (cell == nil) block. Inside this block, also give the text view a unique tag and use this tag property to access the text view from outside the block. See Apple's table view sample code for examples of this pattern, it is being used a lot.