Troubleshoot Data Merge

For iOS applications upgraded from SDK versions 7.x to versions up to 8.0.6, the previous v7.x tags and attributes are retained on the device but not sent to the server. If an application doesn’t reset or regenerate tags and attributes, the device sends empty tags and attributes to the system.

The following sections walk through the requirements for merging datasets successfully.

Upgrade the SDK 

Using SPM, upgrade to the latest version of the SDK for iOS and SFMCSDK for iOS.

Swift Compilation Error 

You may encounter a build failure if the Swift compiler version used to build the SDK doesn’t match the version used by your current Xcode toolchain.

The build fails with this error:

1X86_64-apple-ios-simulator.private.swiftinterface
2
3failed to build module 'PushFeatureSDK'; this SDK is not supported by the compiler (the SDK is built with 'Apple Swift version 6.1.2...', while this compiler is 'Apple Swift version 6.2.3...'). Please select a toolchain which matches the SDK.
4
5'PushFeatureProtocol' is unavailable: cannot find Swift declaration for this protocol.

To resolve this issue, follow these steps to reset your environment:

  1. Clear Derived Data.
  2. Remove the SDK dependencies from your project and then add them back again.
  3. Clean and Run.

Merge Data (Optional) 

The merging tool offers two options to merge attributes and tags: automatic merging and manual merging. In some scenarios, you can choose to defer or avoid merging the datasets. The merging tool defaults to an “opted out” state if you don’t implement either of the merging methods. In the opted out state, tags and attributes aren’t merged from the version 7.x dataset to your current application’s dataset.

Automatic Merging 

The automatic merging option attempts to merge old data into the current dataset, with the current data taking precedence over data within the version 7.x dataset.

The following tables illustrate how automatic merging behaves and how data is merged.

in this tables, key:value pairs are denoted using : as the separator.

Note

Attributes

Prior DatasetCurrent DatasetMerge Result
A:BemptyA:B
emptyA:BA:B
A:B, C:DA:EA:E, C:D
A:BA: clearedA: cleared

Tags

Prior DatasetCurrent DatasetMerge Result
SHIRTSemptySHIRTS
emptyPANTSPANTS
SHIRTSPANTSSHIRTS, PANTS
SHIRTSSHIRTS, PANTSSHIRTS, PANTS

The following code snippets show you how to configure the SDK to attempt an automatic merge.

To ensure the completion callback passed into setAutoMergePolicy is set before SDK initialization, place the following code snippets before SDK initialization.

Note

Swift
1SFMCSdk.setAutoMergePolicy { isMergeSucces in
2    if(!isMergeSuccess) {
3        // ...
4    }
5}
Objective-C
1[SFMCSdk setAutoMergePolicyOnCompletion:^(BOOL isMergeSuccess) {
2    if(!isMergeSuccess) {
3        // ...
4    }
5}];

Manual Merging 

The manual merge option enables you to receive both the prior data and the current data in a callback, providing the opportunity to choose what data ultimately ends up in the final dataset.

You can decide what attributes and tags are set in the current dataset. However, to set attributes and tags accordingly, you must retain the data until the SDK is initialized.

Access to the tags and attributes for versions 7.x and 8.x is provided before SDK initialization.

Important

Swift 

10.x
1class ExampleDelegate: UIResponder, UIApplicationDelegate {
2
3    var setTagsAndAttributes: (() -> ())? = nil
4
5    // ...
6}
7
8// ...
9SFMCSdk.setManualMergePolicy(withHandler: {(v8, v9) in
10
11    self.setTags = {
12        let tags: [String] = // e.g. v9["tags"]
13        MarketingCloudSdk.requestSdk { mc in
14            mc?.addTags(tags)
15        }
16    }
17}
18
19private func handleSDKInitializationCompletion(status: [ModuleInitStatus]) {
20    // ...
21    if moduleStatus.initStatus == .success {
22        // Handle successful initialization for each module
23        switch moduleStatus.moduleName {
24        case .engagement:
25            self.setTags?()
26            // Handle successful initialization for Marketing cloud module
27        }
28    }
29    // ...
30}
31
32// ...
33
34SFMCSdk.initializeSdk(configBuilder.build(), completion: completionHandler)
8.x
1class ExampleDelegate: UIResponder, UIApplicationDelegate {
2
3    var setTagsAndAttributes: (() -> ())? = nil
4
5    // ...
6}
7
8// ...
9SFMCSdk.setManualMergePolicy(withHandler: {(v7, v8) in
10
11    self.setTagsAndAttributes = {
12        let attributes: [String:String] = // e.g. v8["attributes"] as! [String : String]
13        SFMCSdk.identity.setProfileAttributes([ModuleName.push : attributes])
14
15        let tags: [String] = // e.g. v8["tags"]
16        SFMCSdk.requestPushSdk { mp in
17            mp.addTags(tags)
18        }
19    }
20}
21
22// ...
23
24let completionHandler: (OperationResult) -> () = { result in
25    // ...
26    if result == .success {
27        // ...
28        if (SFMCSdk.mp.getStatus() == .operational) {
29            self.setTagsAndAttributes?()
30        }
31        // ...
32    }
33}
34
35// ...
36
37SFMCSdk.initializeSdk(ConfigBuilder().setPush(config: configuration, onCompletion: completionHandler).build())

Objective C 

10.x
1@interface ExampleDelegate : UIResponder <UIApplicationDelegate>
2
3@property (nonatomic, copy) void (^setTags)(void);
4
5// ...
6
7[SFMCSdk setManualMergePolicyWithHandler:^(NSDictionary * _Nonnull v8, NSDictionary * _Nonnull v9) {
8    self.setTags = ^{
9
10        NSArray *tags = // e.g. v9[@"tags"];
11        [SFMarketingCloudSdk requestSdk:^(id<MarketingCloudSdkInterface> _Nonnull mp) {
12          [mp addTags: tags];
13        }];
14    }
15}];
16
17// MARK: - SDK Initialization Completion Handler
18
19- (void)handleSDKInitializationCompletion:(NSArray<SFMCModuleInitStatus *> *)status {
20    // ...
21        if (moduleStatus.initStatus == SFMCSdkOperationResultSuccess) {
22            switch (moduleStatus.moduleName) {
23                case SFMCSdkModuleNameEngagement:
24                    if (self.setTags != nil) {
25                        [self setTags];
26                    }
27                    break;
28            }
29        }
30    // ...
31
32SFMCSdkConfigBuilder *configBuilder = [[SFMCSdkConfigBuilder alloc] init];
33configBuilder = [configBuilder setEngagementWithConfig:pushConfig];
34[SFMCSdk initializeSdk:[configBuilder build] completion:^(NSArray<SFMCModuleInitStatus *> * _Nonnull status) {
35    // Handle completion
36    [self handleSDKInitializationCompletion:status];
37}];
8.x
1@interface ExampleDelegate : UIResponder <UIApplicationDelegate>
2
3@property (nonatomic, copy) void (^setTagsAndAttributes)(void);
4
5// ...
6
7[SFMCSdk setManualMergePolicyWithHandler:^(NSDictionary * _Nonnull v7, NSDictionary * _Nonnull v8) {
8    self.setTagsAndAttributes = ^{
9        NSDictionary *attributes = // e.g. v8[@"attributes"];
10        [[SFMCSdk identity] setProfileAttributes:attributes];
11
12        NSArray *tags = // e.g. v8[@"tags"];
13        [SFMCSdk requestPushSdk:^(id<PushInterface> _Nonnull mp) {
14          [mp addTags: tags];
15        }];
16    }
17}];
18
19// ...
20
21void (^completionHandler)(OperationResult) = ^(OperationResult result) {
22   switch(result) {
23       case OperationResultSuccess:
24            // ...
25            if ([[SFMCSdk mp] getStatus] == ModuleStatusOperational) {
26                if (self.setTagsAndAttributes != nil) {
27                    [self setTagsAndAttributes];
28                }
29            }
30           // ...
31
32           break;
33       // ...
34   }
35}
36
37SFMCSdkConfigBuilder *configBuilder = [[SFMCSdkConfigBuilder alloc] init];
38configBuilder = [configBuilder setPushWithConfig:pushConfig onCompletion:completionHandler];
39[SFMCSdk initializeSdk:[configBuilder build]];

Retry Data Merge 

If you must run the merge tool again, you can attempt the merge multiple times.

Reattempting merges doesn’t roll back the current dataset but enables you to regain access to the data within the old version 7.x dataset.

Swift
1let appId = // your app ID
2let resetSuccess: Bool = SFMCSdk.resetDataPolicy(appId: appId)
3if (resetSuccess) {
4    print("reset succeeded")
5}
Objective-C
1NSString *appId = // your app ID
2BOOL resetSuccess = [SFMCSdk resetDataPolicyWithAppId:appId];
3if(resetSuccess) {
4    NSLog(@"reset succeeded");
5}