Skip to content

Migration Guide: Interstitial Ads (v1.0.4)

This guide helps you migrate from the old static function-based interstitial ad API to the new class-based API with delegate pattern introduced in version 1.0.4.

Overview of Changes

The interstitial ad API has been redesigned to provide better control, improved error handling, and a more flexible lifecycle management through a delegate pattern.

Key Changes

  • Instance-based API: Changed from static functions to a class-based approach with RingierAdSDKInterstitialAd
  • Delegate Pattern: Replaced completion handlers with a comprehensive delegate protocol
  • Enhanced Lifecycle Control: Added reset() method for better resource management
  • Improved Error Handling: More granular error types and detailed error information
  • Better Event Tracking: Separate callbacks for impressions, clicks, and all presentation states

API Comparison

Old API (Before v1.0.4)

swift
// Old: Static functions with completion handlers
RingierAd.loadInterstitialAd(
    params: params,
    keywords: keywords
) { success in
    if success {
        print("Ad loaded")
    } else {
        print("Ad failed to load")
    }
}

RingierAd.showInterstitialAd(
    params: params,
    controller: self
) { success in
    if success {
        print("Ad shown")
    } else {
        print("Ad failed to show")
    }
}

New API (v1.0.4+)

swift
// New: Class-based with delegate pattern
class MyViewController: UIViewController {
    private var interstitialAd: RingierAdSDKInterstitialAd?
    
    func loadAd() {
        interstitialAd = RingierAdSDKInterstitialAd()
        interstitialAd?.delegate = self
        interstitialAd?.load(params: params, keywords: keywords)
    }
}

extension MyViewController: RingierAdSDKInterstitialAdDelegate {
    func interstitialAdDidLoaded() {
        print("Ad loaded")
    }
    
    func interstitialAdDidFailToLoad(error: Error) {
        print("Ad failed to load: \(error)")
    }
    
    // ... other delegate methods
}

Step-by-Step Migration

Step 1: Replace Static Function Calls

Before:

swift
class ArticleViewController: UIViewController {
    
    func loadInterstitialAd() {
        let params = RingierAdInterstitialParams(
            category: "articles",
            placementOrAlias: "interstitial1"
        )
        
        RingierAd.loadInterstitialAd(
            params: params,
            keywords: ["topic": "sports"]
        ) { [weak self] success in
            if success {
                self?.showInterstitialAd(params: params)
            }
        }
    }
    
    func showInterstitialAd(params: RingierAdInterstitialParams) {
        RingierAd.showInterstitialAd(
            params: params,
            controller: self
        ) { success in
            print("Ad presentation result: \(success)")
        }
    }
}

After:

swift
class ArticleViewController: UIViewController {
    
    // Add property to hold the interstitial ad instance
    private var interstitialAd: RingierAdSDKInterstitialAd?
    
    func loadInterstitialAd() {
        // Create instance and set delegate
        interstitialAd = RingierAdSDKInterstitialAd()
        interstitialAd?.delegate = self
        
        let params = RingierAdInterstitialParams(
            category: "articles",
            placementOrAlias: "interstitial1"
        )
        
        // Load the ad
        interstitialAd?.load(params: params, keywords: ["topic": "sports"])
    }
}

// Add delegate conformance
extension ArticleViewController: RingierAdSDKInterstitialAdDelegate {
    
    func adDidLoad() {
        // Ad is ready, show it when appropriate
        interstitialAd?.show(from: self)
    }
    
    func adDidFailToLoad(error: RingierAdSDKInterstitialError) {
        print("Failed to load ad: \(error.localizedDescription)")
    }
    
    func adWillPresent() {
        // Called before ad is presented
    }
    
    func adDidDismiss() {
        print("Ad was dismissed")
        // Clean up
        interstitialAd?.reset()
    }
    
    func adWillDismiss() {
        // Called before ad is dismissed
    }
    
    func adDidFailToPresent(error: RingierAdSDKInterstitialError) {
        print("Failed to present ad: \(error.localizedDescription)")
    }
    
    func adDidRecordImpression() {
        // Track impression
    }
    
    func adDidRecordClick() {
        // Track click
    }
}

Step 2: Update Lifecycle Management

Before:

swift
// Old API: No explicit cleanup needed
// SDK managed the lifecycle internally

After:

swift
// New API: Explicit lifecycle management

func interstitialAdDidDismiss() {
    // Always reset after showing
    interstitialAd?.reset()
    
    // Optionally load next ad
    loadNextAd()
}

deinit {
    // Clean up in deinit
    interstitialAd?.reset()
}

Step 3: Handle Errors Properly

Before:

swift
RingierAd.loadInterstitialAd(params: params, keywords: [:]) { success in
    if !success {
        // Generic failure, no error details
        print("Failed to load")
    }
}

After:

swift
func adDidFailToLoad(error: RingierAdSDKInterstitialError) {
    // Detailed error information with type-safe error handling
    switch error {
    case .missingConfig:
        print("SDK not configured")
    case .missingPlacement:
        print("Placement not found in config")
    case .placementNotFound:
        print("Invalid placement parameters")
    case .loadFailed(let underlyingError):
        print("Load failed: \(underlyingError)")
    default:
        print("Error: \(error.localizedDescription)")
    }
}

func adDidFailToPresent(error: RingierAdSDKInterstitialError) {
    // Handle presentation errors with type-safe error handling
    switch error {
    case .adNotReady:
        print("Ad was not loaded before showing")
    case .invalidViewController:
        print("Invalid view controller provided")
    case .presentationFailed(let underlyingError):
        print("Presentation failed: \(underlyingError)")
    default:
        print("Error: \(error.localizedDescription)")
    }
}

Step 4: Track Ad Events

Before:

swift
// Old API: Limited event tracking
// Only load and show success/failure

After:

swift
// New API: Comprehensive event tracking

func adWillPresent() {
    // Pause ongoing activities, mute audio, etc.
    pauseVideo()
}

func adDidRecordImpression() {
    // Track impression in analytics
    Analytics.trackEvent("interstitial_impression")
}

func adDidRecordClick() {
    // Track click in analytics
    Analytics.trackEvent("interstitial_click")
}

func adWillDismiss() {
    // Prepare to resume activities
}

func adDidDismiss() {
    // Resume activities
    resumeVideo()
}

Common Migration Patterns

Pattern 1: Sequential Ad Loading

Before:

swift
func loadAdAndShow() {
    RingierAd.loadInterstitialAd(params: params, keywords: [:]) { [weak self] success in
        if success {
            RingierAd.showInterstitialAd(params: params, controller: self!) { _ in }
        }
    }
}

After:

swift
private var interstitialAd: RingierAdSDKInterstitialAd?

func loadAdAndShow() {
    interstitialAd = RingierAdSDKInterstitialAd()
    interstitialAd?.delegate = self
    interstitialAd?.load(params: params, keywords: [:])
}

func adDidLoad() {
    // Automatically show when ready
    interstitialAd?.show(from: self)
}

Pattern 2: Preloading with Deferred Display

Before:

swift
var isAdReady = false

func preloadAd() {
    RingierAd.loadInterstitialAd(params: params, keywords: [:]) { [weak self] success in
        self?.isAdReady = success
    }
}

func showAdWhenReady() {
    if isAdReady {
        RingierAd.showInterstitialAd(params: params, controller: self) { _ in }
    }
}

After:

swift
private var interstitialAd: RingierAdSDKInterstitialAd?
private var isAdReady = false

func preloadAd() {
    interstitialAd = RingierAdSDKInterstitialAd()
    interstitialAd?.delegate = self
    interstitialAd?.load(params: params, keywords: [:])
}

func showAdWhenReady() {
    if isAdReady {
        interstitialAd?.show(from: self)
    }
}

func adDidLoad() {
    isAdReady = true
}

func adDidFailToLoad(error: RingierAdSDKInterstitialError) {
    isAdReady = false
}

Error Types Reference

The new API introduces RingierAdSDKInterstitialError enum with detailed error cases:

Error CaseCodeDescription
missingConfig1001SDK configuration is missing
missingPlacement1002Ad placement not found in config
placementNotFound1003Invalid placement parameters
adNotReady1004Ad not loaded before show()
loadFailed(underlyingError)1005Ad loading failed
presentationFailed(underlyingError)1006Ad presentation failed
invalidViewController1007Invalid view controller

Best Practices

  1. Always Keep Strong Reference: Store the RingierAdSDKInterstitialAd instance as a property

    swift
    private var interstitialAd: RingierAdSDKInterstitialAd? // ✅ Good
    // Not as a local variable in a function
  2. Implement All Delegate Methods: Even if you don't need all callbacks, implement them for completeness

  3. Reset After Use: Always call reset() after showing an ad

    swift
    func interstitialAdDidDismiss() {
        interstitialAd?.reset()
    }
  4. Handle All Error Cases: Provide fallback behavior for load and presentation failures

  5. Clean Up in deinit: Release resources properly

    swift
    deinit {
        interstitialAd?.reset()
    }

Troubleshooting

Issue: Ad not showing

Problem: Called show(from:) but nothing happens

Solution: Make sure you:

  1. Waited for adDidLoad() before calling show(from:)
  2. Kept a strong reference to the RingierAdSDKInterstitialAd instance
  3. Set the delegate before calling load()

Issue: Delegate methods not called

Problem: Delegate methods never fire

Solution:

swift
// ❌ Wrong: Weak reference released immediately
func loadAd() {
    var ad = RingierAdSDKInterstitialAd()
    ad.delegate = self
    ad.load(params: params, keywords: [:])
}

// ✅ Correct: Strong property reference
private var interstitialAd: RingierAdSDKInterstitialAd?

func loadAd() {
    interstitialAd = RingierAdSDKInterstitialAd()
    interstitialAd?.delegate = self
    interstitialAd?.load(params: params, keywords: [:])
}

Issue: Memory leak

Problem: Ads not being deallocated

Solution: Always call reset() when done:

swift
func adDidDismiss() {
    interstitialAd?.reset()
}

deinit {
    interstitialAd?.reset()
}

Need Help?

If you encounter issues during migration:

  • Check the Interstitial Ads documentation
  • Review the complete examples in the guide
  • Ensure you're using RingierAdSDK v1.0.4 or later