> ## Documentation Index
> Fetch the complete documentation index at: https://docs.cloudx.io/llms.txt
> Use this file to discover all available pages before exploring further.

# First Look

> 在 iOS 中优先尝试 CloudX，同时保留现有聚合广告位作为回退

First Look 让 CloudX 优先获得广告位填充机会，同时保留您现有的聚合设置作为回退路径。建议先从一个广告位开始，验证加载和展示行为后，再扩展到更多广告位。

此示例使用 AdMob 插屏广告作为回退。相同模式也适用于其他回退聚合平台：先加载 CloudX；只有当 CloudX 未加载成功时才加载回退广告；当两个来源都未准备好时，让应用流程继续。

<Info>
  创建控制器前，请先完成 CloudX 和 Google Mobile Ads 初始化。控制器外部仍应保留您现有的频控、重试和广告位触发时机规则。
</Info>

```swift FirstLookInterstitialController.swift theme={null}
import CloudXCore
import GoogleMobileAds
import UIKit

@MainActor
final class FirstLookInterstitialController: NSObject {
    enum Source {
        case cloudX
        case adMob
    }

    protocol Listener: AnyObject {
        func firstLookInterstitialController(_ controller: FirstLookInterstitialController, didLoad source: Source)
        func firstLookInterstitialController(_ controller: FirstLookInterstitialController, didFailToLoad source: Source, message: String?)
        func firstLookInterstitialController(_ controller: FirstLookInterstitialController, didShow source: Source)
        func firstLookInterstitialController(_ controller: FirstLookInterstitialController, didFailToShow source: Source, message: String?)
        func firstLookInterstitialController(_ controller: FirstLookInterstitialController, didClose source: Source)
        func firstLookInterstitialController(_ controller: FirstLookInterstitialController, didClick source: Source)
    }

    weak var listener: Listener?

    private weak var viewController: UIViewController?
    private let cloudXInterstitial: CLXInterstitial
    private let adMobAdUnitId: String
    private var adMobInterstitial: InterstitialAd?
    private var isLoadingCloudX = false
    private var isLoadingAdMob = false

    init?(
        viewController: UIViewController,
        cloudXAdUnitId: String,
        adMobAdUnitId: String
    ) {
        guard let cloudXInterstitial = CloudXCore.shared.createInterstitial(adUnitId: cloudXAdUnitId) else {
            return nil
        }

        self.viewController = viewController
        self.cloudXInterstitial = cloudXInterstitial
        self.adMobAdUnitId = adMobAdUnitId
        super.init()
        self.cloudXInterstitial.delegate = self
    }

    func load() {
        guard !isLoadingCloudX,
              !isLoadingAdMob,
              !cloudXInterstitial.isReady,
              adMobInterstitial == nil else {
            return
        }

        isLoadingCloudX = true
        cloudXInterstitial.load()
    }

    func show() -> Bool {
        guard let viewController else {
            return false
        }

        if cloudXInterstitial.isReady {
            cloudXInterstitial.show(from: viewController)
            return true
        }

        return showAdMobFallback(from: viewController)
    }

    func destroy() {
        cloudXInterstitial.destroy()
        adMobInterstitial = nil
        listener = nil
    }

    private func loadAdMobFallback() {
        guard !isLoadingAdMob, adMobInterstitial == nil else {
            return
        }

        isLoadingAdMob = true
        InterstitialAd.load(with: adMobAdUnitId, request: Request()) { [weak self] ad, error in
            guard let self else { return }

            self.isLoadingAdMob = false

            if let error {
                self.adMobInterstitial = nil
                self.listener?.firstLookInterstitialController(self, didFailToLoad: .adMob, message: error.localizedDescription)
                return
            }

            guard let ad else {
                self.adMobInterstitial = nil
                self.listener?.firstLookInterstitialController(self, didFailToLoad: .adMob, message: nil)
                return
            }

            ad.fullScreenContentDelegate = self
            self.adMobInterstitial = ad
            self.listener?.firstLookInterstitialController(self, didLoad: .adMob)
        }
    }

    private func showAdMobFallback(from viewController: UIViewController) -> Bool {
        guard let adMobInterstitial else {
            return false
        }

        adMobInterstitial.present(from: viewController)
        return true
    }
}

extension FirstLookInterstitialController: CLXInterstitialDelegate {
    func didLoad(_ ad: CLXAd) {
        isLoadingCloudX = false
        listener?.firstLookInterstitialController(self, didLoad: .cloudX)
    }

    func didFailToLoadAd(_ adUnitId: String, error: CLXError) {
        isLoadingCloudX = false
        loadAdMobFallback()
    }

    func didDisplay(_ ad: CLXAd) {
        listener?.firstLookInterstitialController(self, didShow: .cloudX)
    }

    func didFailToDisplay(_ ad: CLXAd, error: CLXError) {
        if let viewController, showAdMobFallback(from: viewController) {
            return
        }

        listener?.firstLookInterstitialController(self, didFailToShow: .cloudX, message: error.localizedDescription)
    }

    func didHide(_ ad: CLXAd) {
        listener?.firstLookInterstitialController(self, didClose: .cloudX)
    }

    func didClick(_ ad: CLXAd) {
        listener?.firstLookInterstitialController(self, didClick: .cloudX)
    }
}

extension FirstLookInterstitialController: FullScreenContentDelegate {
    func adWillPresentFullScreenContent(_ ad: FullScreenPresentingAd) {
        adMobInterstitial = nil
        listener?.firstLookInterstitialController(self, didShow: .adMob)
    }

    func adDidDismissFullScreenContent(_ ad: FullScreenPresentingAd) {
        adMobInterstitial = nil
        listener?.firstLookInterstitialController(self, didClose: .adMob)
    }

    func ad(_ ad: FullScreenPresentingAd, didFailToPresentFullScreenContentWithError error: Error) {
        adMobInterstitial = nil
        listener?.firstLookInterstitialController(self, didFailToShow: .adMob, message: error.localizedDescription)
    }

    func adDidRecordClick(_ ad: FullScreenPresentingAd) {
        listener?.firstLookInterstitialController(self, didClick: .adMob)
    }
}
```

在广告位触发时调用 `show()`。如果返回 `false`，表示 CloudX 和回退广告都没有准备好，此时应继续应用流程，不展示广告。

```swift theme={null}
if firstLookInterstitial?.show() != true {
    continueToNextScreen()
}
```

广告展示、关闭或最终失败后，请在您的应用准备好下一次广告位机会时再次调用 `load()`。

<Tip>
  此示例采用懒加载回退：只有 CloudX 加载失败后才加载 AdMob。除非 CloudX 针对您的应用建议其他上线策略，否则不要并行加载两个来源。
</Tip>
