# In Feed

## Scenario

* Insert Ad into  `UITableView` while users are scrolling it.

## Ad Formats Supported

* Card Ad
* Native Ad

## How to Integrate

### CrystalExpress™ SDK provides `CEInFeedHelper` to simplify in-feed integration of Card Ad and Native Ad. Please follow the step below: <a href="#crystalexpress-tm-sdk-provides-ceinfeedhelper-to-simplify-in-feed-integration-of-card-ad-and-native" id="crystalexpress-tm-sdk-provides-ceinfeedhelper-to-simplify-in-feed-integration-of-card-ad-and-native"></a>

### Step 0 : Put CEInFeedHelper folder into your project folder <a href="#step-1-copy-the-adsource-component-under-infeed-folder" id="step-1-copy-the-adsource-component-under-infeed-folder"></a>

Please put the whole folder of CEInFeedHelper from CrystalExpress SDK Sample code provided into the folder of your App project.

### Step 1: Create appropriate CEInFeedHelper for your scenario

There are 2 ways to integrate CEInFeedHelper, placement integration and tag integration. Main difference between those 2 integrations is that tag integration is aimed to handle Ad targeting for specific channels.

Under placement integration, publishes provide the placement to helper directly. On the other hand, the helper will get placements for the tag from tag settings from our dashboard

* Placement integration of Card Ad format:

```swift
let inFeedHelper = CEInFeedHelper(placement: "YOUR_PLACEMENT_ID", adSource: CEIFCardAdSource())
```

* Placement integration of Native Ad format:

```swift
let inFeedHelper = CEInFeedHelper(placement: "YOUR_PLACEMENT_ID", adSource: CEIFNativeAdSource(layoutDelegate: self))
```

* Tag integration of Card Ad format:

```swift
let inFeedHelper = CEInFeedHelper(tag: "YOUR_TAG_ID", adSource: CEIFCardAdSource())
```

* Tag integration of Native Ad format:

```swift
let inFeedHelper = CEInFeedHelper(tag: "YOUR_TAG_ID", adSource: CEIFNativeAdSource(layoutDelegate: self))
```

### Step 1-2(Native Only): Implement Native Ad Source Delegate

You can set Native Ad layout properly by implementing this delegate. Moreover, the frame of this view returned will be the same as the ad view received from the helper, so it would be better to set the width of Ad view equal to table view.

```swift
extension YOUR_INFEED_VIEWCONTROLLER : CEIFNativeAdSourceLayoutDelegate {
    func view(with nativeAd: CENativeAd!) -> UIView! {
        // Set width of Ad view
        // Instantiate MediaView
        // Get strings of title, description, and call to action
        // Customized Ad view layout
        // Register NativeAd
        // Return Ad view
        ...
        ...
    }
}
```

### Step 2: Create CEDataSourceHelper by CEInFeedHelper

CEDataSourceHelper can help you know adjusted position and related info of Ad items on the tableview.

```swift
inFeedHelper.eventDelegate = self
self.dataSourceHelper = CEDataSourceHelper(inFeedHelper: inFeedHelper, delegate: self)
```

### Step 3: Add the Ad count into numberOfRowsInSection

Add the number of Ad items by CEDataSourceHelper into numberOfRowsInSection.

```swift
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        let result = "TOTAL_ITEM_NUMBER OF ORIGINAL UITABLEVIEW" + (self.dataSourceHelper?.adCount() ?? 0)
        return result
}
```

### Step 4:  Get Ad view from CEDataSourceHelper

#### Case:  Ad is not going to show right away

* Get Ad view from CEDataSourceHelper by the index number you assign and get original data's height with shifted path in `estimatedHeightForRowAt`.

```swift
func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
        if let adView = self.dataSourceHelper?.peekAdView(for: indexPath) {
            // ToDo
            // If receiving non-nil value, the cell should be ad cell.
            // Return the height of the ad cell according the ad view.
            // ...
        }
        return cellHeight(forPath: self.shiftedPath(indexPath), tableView: tableView)
}
```

#### Case: Ad is going to show right away

* Get Ad view from CEDataSourceHelper by the index number you assign and get original data's height with shifted path in `cellForRowAt`.

```swift
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        if let adView = self.dataSourceHelper?.getAdView(for: indexPath) {
            // ToDO
            // If receiving non-nil value, the cell should be ad cell.
            // Declare the ad cell in customized way.
            // Return the ad cell according the ad view.
            ...
            ...
        }
        return createCell(forPath: self.shiftedPath(indexPath), tableView: tableView)
}
```

* Get Ad view from CEDataSourceHelper by the index number you assign and get original data's height with shifted path in `heightForRowAt` .

```swift
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
        if let adView = self.dataSourceHelper?.getAdView(for: indexPath) {
            // ToDo
            // If receiving non-nil value, the cell should be ad cell.
            // Return the height of the ad cell according the ad view.
            ...
            ...
        }
        return cellHeight(forPath: self.shiftedPath(indexPath), tableView: tableView)
}
```

### Step 5: Get original data's height with shifted path

```swift
func shiftedPath(_ indexPath:IndexPath) -> IndexPath {
        // ObjC -> Swift optional handling.
        return self.dataSourceHelper?.shiftedPath(for: indexPath) ?? indexPath
}
```

### Step 6: Insert new rows for just new Ads

Update the Ad count to maintain data integrity and avoid exception of UITableView.

```swift
func toInsertRows(_ rowsCount: Int) {
    guard rowsCount > 0 else {
        return
    }
    let currentRowInTable = self.table.numberOfRows(inSection: 0)
    var rows = [IndexPath]()
    for i in 0 ... (rowsCount-1) {
        rows.append(IndexPath(row: currentRowInTable + i, section: 0))
    }
    self.table.insertRows(at: rows, with:.none)
}
```

### Step 7: Implement delegate of CEInFeedHelper (Optional \*)

By implementing delegate, you can get Ad event callback from Ad source.

```swift
extension DemoInFeedSingleViewController : CEIFHelperADEventDelegate {
    func adDidImpression(_ index: UInt, ad adObj: Any!) {

    }

    func adDidClicked(_ index: UInt, ad adObj: Any!) {

    }

    func adDidMute(_ index: UInt, ad adObj: Any!) {

    }

    func adDidUnmute(_ index: UInt, ad adObj: Any!) {

    }

    func adVideoDidStart(_ index: UInt, ad adObj: Any!) {

    }

    func adVideoDidEnd(_ index: UInt, ad adObj: Any!) {

    }

    func adVideoProgress(_ index: UInt, ad adObj: Any!, duration: Int32, position: Int32) {

    }
}
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://intowow.gitbook.io/crystalexpress-documentation-v3-x/ios-sdk/integration-scenario/in-feed.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
