EVGCampaignHandler Block Reference

Declared in EVGCampaign.h

Block Definition

EVGCampaignHandler

Callback implemented by the app to handle potential custom ‘Data’ <campaigns> served in response to Evergage actions generated by the user interacting with the app.

typedef void (^EVGCampaignHandler) (EVGCampaign *__nonnull campaign)

Discussion

See Mobile Data Campaigns Guide for additional info, and [EVGContext setCampaignHandler:forTarget:] for lifecycle details.

Usage Details:

  • For a view controller, it is recommended to setup handlers in viewWillAppear:. See examples below.
  • Validate the expected campaign data/JSON before processing, since campaigns are dynamic and designed in the Evergage web app.
  • The same campaign could be re-served, so when applicable, check if the same content is already active. For example, there’s no need to re-render the same message/UI to the user if it’s still visible. This is especially true when testing a specific experience, see [Evergage(Swizzling) handleOpenURL:].
  • Follow best practices using weak references within the handler block, to avoid retaining objects in memory longer than expected, which could lead to memory bloat and unexpected behavior. Examples correctly using weak reference:

Example that expects the featured product’s name and updates a UILabel on screen:

Obj-C:

// In ViewController.m

- (void)viewWillAppear:(BOOL)animated {
    [super viewWillAppear:animated];

    __weak typeof(self) weakSelf = self;
    EVGCampaignHandler handler = ^(EVGCampaign * __nonnull campaign) {
        // Safest to perform a single method/operation on weakSelf, which will simply be a no-op if weakSelf is nil:
        [weakSelf handleCampaign:campaign];
    };

    // The target string uniquely identifies the expected data schema - here, a featured product:
    [self.evergageScreen setCampaignHandler:handler forTarget:@"Featured Product"];
}

- (void)handleCampaign:(nonnull EVGCampaign *)campaign {
    // Validate the campaign data since it's dynamic JSON. Avoid processing if fails.
    NSString *featuredProductName = campaign.data[@"featuredProductName"];
    if (![featuredProductName isKindOfClass:[NSString class]] || !featuredProductName.length) {
        return;
    }

    // Check if the same content is already visible/active (see Usage Details above).
    if (self.activeCampaign && [self.activeCampaign isEqual:campaign]) {
        NSLog(@"Ignoring campaign name %@ since equivalent content is already active", campaign.campaignName);
        return;
    }

    // Track the impression for statistics even if the user is in the control group.
    [self.evergageScreen trackImpression:campaign];

    // Only display the campaign if the user is not in the control group.
    if (!campaign.isControlGroup) {
        // Keep active campaign as long as needed for (re)display and comparison
        self.activeCampaign = campaign;
        NSLog(@"New active campaign name %@ for target %@ with data %@",
              campaign.campaignName, campaign.target, campaign.data);

        // Display campaign content
        self.featuredProductLabel.text = [NSString stringWithFormat:@"Our featured product is %@!", featuredProductName];
    }
}

Swift:

// In ViewController.swift

override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)

    // Note self is captured weakly
    let handler = { [weak self] (campaign: EVGCampaign) -> Void in
        // Safest to perform a single method/operation on weakSelf, which will simply be a no-op if weakSelf is nil:
        self?.handleCampaign(campaign: campaign)
    }

    // The target string uniquely identifies the expected data schema - here, a featured product:
    evergageScreen?.setCampaignHandler(handler, forTarget: "Featured Product")
}

func handleCampaign(campaign: EVGCampaign) {
    // Validate the campaign data since it's dynamic JSON. Avoid processing if fails.
    guard let featuredProductName = campaign.data["featuredProductName"] as? String
        else { return }
    if (featuredProductName.isEmpty) { return }

    // Check if the same content is already visible/active (see Usage Details above).
    if (activeCampaign && activeCampaign.equals(campaign)) {
    NSLog("Ignoring campaign name %@ since equivalent content is already active",
          campaign.campaignName)
        return
    }

    // Track the impression for statistics even if the user is in the control group.
    evergageScreen?.trackImpression(campaign)

    // Only display the campaign if the user is not in the control group.
    if (!campaign.isControlGroup) {
        // Keep active campaign as long as needed for (re)display and comparison
        activeCampaign = campaign
        NSLog("New active campaign name %@ for target %@ with data %@",
              campaign.campaignName, campaign.target, campaign.data)

        featuredProductLabel.text = String(format: "Our featured product is %@!", featuredProductName)
    }
}

Declared In

EVGCampaign.h