We previously talked about docking AdMob ads to the bottom or top of a UITableView . In response to that post, we’ve had a lot of developers asking us about embedding AdMob ads within the UITableView cells, so we wanted to share how this can be best achieved.
Challenge
Placing ads within a Table View in iOS as list items can bring up a number of issues:
Inflated impression numbers because tables in iOS refresh when the user scrolls.
The one-to-one mapping between data in the Table View and the application’s model will usually be lost.
Choosing A Solution
Table Views in iOS are populated by implementing the tableView:cellForRowAtIndexPath: method. Cell objects are often reused so that new ones aren’t instantiated each time the Table View is refreshed (by a scroll for example). There are two ways that ads can be implemented within Table View cells:
Only use one GADBannerView throughout the table. This would mean that the same ad is displayed in different cells in the table (preferred).
Leverage dequeueReusableCellWithIdentifier: so that GADBannerViews are created only when new cells are created.
Using one GADBannerView throughout the table does decrease ad diversity but generally increases the CTR for the ads that are shown because the user will more likely see the ads that are displayed. The example below will show how to implement this approach as it is the better practice.
Solution - Single GADBannerView Method
For the purposes of this example, let’s assume that every 10th element in the list is going to be an ad. This means tableView:cellForRowAtIndexPath: will be set up with a conditional that modifies the placement of the GADBannerView for every tenth cell:
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath {
int row = [indexPath row];
// Assume that kFrequencyAdsInCells is 10 so every 10th row is an ad
// Don't want first item to be an ad so use 10-1=9 instead of 0
if ((row % kFrequencyAdsInCells) == (kFrequencyAdsInCells)) {
cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
//Need to create a new cell object
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero
reuseIdentifier:CellIdentifier]
autorelease];
}
// If bannerView_ has a superview, then it has been added to a cell
if (!bannerView_.superview) {
// First ad request made, make the ad request and add it to this cell
[self requestAd];
}
// The banner will be removed from the other cell and put into here
[cell.contentView addSubview:bannerView_];
}
…
Since ads are being inserted into the Table View now, any previous mapping to data in the model will be lost. Some quick math is necessary here to figure out how the rows in the Table View line up.
// Complete in cellForRowAtIndexPath: if not ad
// Make sure we get all of the items from our model
row = row - floor((float)row/kFrequencyAdsInCells);
cell.textLabel.text = [dataController_ objectInListAtIndex:row];
The methods tableView:NumberOfRowsInSection: and tableView:heightForRowAtIndexPath: will need to be modified as well. The method tableView:NumberOfRowsInSection: would now return the number of elements (including ads in that number) and tableView:heightForRowAtIndexPath: would return the height of an ad for every tenth cell, respectively.
If you have any questions about embedding ads within a UITableView, or even any questions about the SDK in general, feel free to post them in our forum . Keep an eye out for AdCatalog v2 for all kinds of advanced layouts options integrated in the project.
- Raj Parameswaran , AdMob Team