App Crash only on App Review

I have a weird problem with my app. I needed to update the metadata on App Store connect and uploaded a new build to App Store. The only thing that was changed in code is two strings with version number. Everything else is exactly the same as a version that is live on the App Store (which works fine). I got a rejection with 2.1.0 Performance: App Completeness reason, turned out my app crashes on launch on reviewers device. I thought that this maybe a one time problem and tried to upload a new build with same results. Attached crash report.

Looks like Facebook SDK(?) crashing the app? And what is about Realm? The problem is I can't reproduce the crash anywhere. Simulator or 5 real devices including same phone model as in crash log. Tried different combinations of Debug/Release, setting Exception Breakpoints without any luck.

Will be really thankful for any insight on how to approach this problem or what is going on here. Thank you very much!

Hi, double-checking some hypotheses:

  • I've noticed that Apple reviewers use an iPad to test. Did you try to test on that device?
  • Also, they are logging in from the USA - does your app work from that location? In our app, we forgot we restricted users to Europe and login wasn't working.

Best, André

@andrefreitas

Hi, thank you very much for your answer.

  • i see in the crash log that device is now the iPhone, so probably things changed. But just to make sure I ran on iPad now with same result - all works fine.
  • I don't have user account in the app so no restrictions like this

The problem is that the build of the app that is currently live on App Store (which was approved) is same as this one that crashes - and it works fine. The only thing that changed between builds is two strings with version number and as far as I know nothing relies on those strings. Looks like Realm is crashing on launch (I have database creation on first run) and probably review configuration is different from TestFlight/XCode/App Store version?

Looks like Facebook SDK(?) crashing the app?

I’m not sure how you came to that conclusion. Don’t mistake the FB in FBSScene for Facebook. That stands for FrontBoardServices, which is a system library that’s involved in app lifecycle management.

And what is about Realm?

That’s more in the ballpark. Looking at the crash report it’s clear that your app has crashed due to an unhandled language exception and that this exception is coming out of Realm in frame 2 as the result of your call in frame 5. If you have Realm source code you should symbolicate frame 2 to get a file and line number and then see what that’s complaining about. For details on how to do this, see Adding Identifiable Symbol Names to a Crash Report.

If you don’t have Realm source code, you should ask the Realm folks about this.

Similarly, for frames 11 through 9 and 7 through 5: You need to symbolicate these to find out what part of your code this is.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

@eskimo

Hello, thank you very much for your answer.

Looks like Facebook SDK(?) crashing the app?

I’m not sure how you came to that conclusion. Don’t mistake the FB in FBSScene for Facebook. That stands for FrontBoardServices, which is a system library that’s involved in app lifecycle management.

Yeah I already understood regarding FrontBoardServices, the last thing that I have added to my code was Facebook SDK thats why it got me thinking that FB stands for Facebook yes, sorry about that:)

If you have Realm source code you should symbolicate frame 2 to get a file and line number and then see what that’s complaining about. For details on how to do this, see Adding Identifiable Symbol Names to a Crash Report. If you don’t have Realm source code, you should ask the Realm folks about this.

I have Realm source code but I am not sure how to proceed further. I have symbolicated crash reports I got from App Review as per "Symbolicate the Crash Report in Xcode" in your link and this is what I have included in initial post. Not sure what should I do further here?

I have Realm source code but I am not sure how to proceed further.

OK, let’s see if we can fix that. Looking at your crash report excerpt I see this:

2 Realm      … RLMAccessorContext::createObject(objc_object*, realm::CreatePolicy, bool, realm::ObjKey) + 1776
3 Realm      … RLMAddObjectToRealm + 264
4 RealmSwift … Realm.add(_:update:) + 279776 …

That means that somewhere in the Binary Images section of the crash report there must be Realm and RealSwift binaries. Each of those will have an associated UUID. To symbolicate your crash report you need to find the .dSYM files whose UUID matches those UUIDs.

If you built those binaries from source code, the build process should have creating corresponding .dSYM files. If it didn’t, you need to adjust your build settings so that it does.

If you use binaries built by someone else, you’ll need to get the .dSYM files from them.

You can check you have the right files by matching up UUID, as discussed in Adding Identifiable Symbol Names to a Crash Report.

Once you have the right .dSYM files, the symbolication process should be able to map addresses to source files and line numbers.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

@eskimo

Thank you very much! Here is what I have now:

Last Exception Backtrace:
0   CoreFoundation                	       0x1aaf29288 __exceptionPreprocess + 220
1   libobjc.A.dylib               	       0x1c3c23744 objc_exception_throw + 60
2   Realm                         	       (anonymous namespace)::managedSetter(RLMProperty*, char const*) (in Realm) (RLMAccessor.mm:383)
3   Realm                         	       +[RLMObjectSchema schemaForObjectClass:] (in Realm) (RLMObjectSchema.mm:140)
4   RealmSwift                    	       Realm.add(_:update:) (in RealmSwift) (Realm.swift:438)
5   AppName             	      		   one-time initialization function for pictureObjectIDandWordArray (in AppName) (TestWords.swift:179)
6   AppName             	               specialized TopVideoCard.isChosen.willset (in AppName) (TopVideoCard.swift:91)
7   AppName             	               one-time initialization function for testCategories2 (in AppName) (TestWords.swift:344)
8   RealmSwift                    	       Realm.write<A>(withoutNotifying:_:) (in RealmSwift) (Realm.swift:255)
9   AppName             	               one-time initialization function for pictureObjectIDandWordArray (in AppName) (<compiler-generated>:0)
10  AppName             	               AppDelegate.application(_:didFinishLaunchingWithOptions:) (in AppName) (AppDelegate.swift:257)
11  AppName             	               AppDelegate.application(_:didFinishLaunchingWithOptions:) (in AppName) (<compiler-generated>:0)
12  UIKitCore                     	       0x1ad62f72c -[UIApplication _handleDelegateCallbacksWithOptions:isSuspended:restoreState:] + 340
13  UIKitCore                     	       0x1ad816564 -[UIApplication _callInitializationDelegatesWithActions:forCanvas:payload:fromOriginatingProcess:] + 3572
14  UIKitCore                     	       0x1ad7ff118 -[UIApplication _runWithMainScene:transitionContext:completion:] + 1180
15  UIKitCore                     	       0x1ad65cd34 -[_UISceneLifecycleMultiplexer completeApplicationLaunchWithFBSScene:transitionContext:] + 152
16  UIKitCore                     	       0x1ad4b73b4 _UIScenePerformActionsWithLifecycleActionMask + 104
17  UIKitCore                     	       0x1ad5e1d90 __101-[_UISceneLifecycleMultiplexer 

Here is parts of those files (with line number after //:

RLMAccessor:

    id managedSetter(RLMProperty *prop, const char *type) {
    if (prop.array && prop.type != RLMPropertyTypeLinkingObjects) {
        return makeSetter<id<NSFastEnumeration>>(prop);
    }

    bool boxed = prop.optional || *type == '@';
    switch (prop.type) {
        case RLMPropertyTypeInt:
            if (boxed) {
                return makeSetter<NSNumber<RLMInt> *>(prop);
            }
            switch (*type) {
                case 'c': return makeSetter<char, long long>(prop);
                case 's': return makeSetter<short, long long>(prop);
                case 'i': return makeSetter<int, long long>(prop);
                case 'l': return makeSetter<long, long long>(prop);
                case 'q': return makeSetter<long long>(prop);
                default:
                    @throw RLMException(@"Unexpected property type for Objective-C type code");
            }
        case RLMPropertyTypeFloat:
            return boxed ? makeSetter<NSNumber<RLMFloat> *>(prop) : makeSetter<float>(prop); // line 383
        case RLMPropertyTypeDouble:
            return boxed ? makeSetter<NSNumber<RLMDouble> *>(prop) : makeSetter<double>(prop);
        case RLMPropertyTypeBool:
            return boxed ? makeSetter<NSNumber<RLMBool> *>(prop) : makeSetter<BOOL, bool>(prop);
        case RLMPropertyTypeString:         return makeSetter<NSString *>(prop);
        case RLMPropertyTypeDate:           return makeSetter<NSDate *>(prop);
        case RLMPropertyTypeData:           return makeSetter<NSData *>(prop);
        case RLMPropertyTypeAny:            return nil;
        case RLMPropertyTypeLinkingObjects: return nil;
        case RLMPropertyTypeObject:         return makeSetter<RLMObjectBase *>(prop);
        case RLMPropertyTypeObjectId:       return makeSetter<RLMObjectId *>(prop);
        case RLMPropertyTypeDecimal128:     return makeSetter<RLMDecimal128 *>(prop);
    }
}

RLMObjectSchema:

   if (allProperties.count != [NSSet setWithArray:[allProperties valueForKey:@"name"]].count) {
        NSCountedSet *countedPropertyNames = [NSCountedSet setWithArray:[allProperties valueForKey:@"name"]];
        NSArray *duplicatePropertyNames = [countedPropertyNames filteredSetUsingPredicate:[NSPredicate predicateWithBlock:^BOOL(id object, NSDictionary *) { // line 140
            return [countedPropertyNames countForObject:object] > 1;
        }]].allObjects;

        if (duplicatePropertyNames.count == 1) {
            @throw RLMException(@"Property '%@' is declared multiple times in the class hierarchy of '%@'", duplicatePropertyNames.firstObject, className);
        } else {
            @throw RLMException(@"Object '%@' has properties that are declared multiple times in its class hierarchy: '%@'", className, [duplicatePropertyNames componentsJoinedByString:@"', '"]);
        }
    }

Realm.swift

public func add(_ object: Object, update: UpdatePolicy = .error) {

        if update != .error && object.objectSchema.primaryKeyProperty == nil {

            throwRealmException("'\(object.objectSchema.className)' does not have a primary key and can not be updated")

        }

        // remove any observers still attached to the Realm.

        // if not using SwiftUI, this is a noop

        if #available(iOS 13.0, macOS 10.15, tvOS 13.0, watchOS 6.0, *) {

            SwiftUIKVO.removeObservers(object: object)

        }

        RLMAddObjectToRealm(object, rlmRealm, RLMUpdatePolicy(rawValue: UInt(update.rawValue))!)

    } // line 438

Thank you very much for your help!

I’m not idea how you’re getting from frame 3 to frame 2, but the code at frame 2 suggests that the exception is the result of some sort of runtime type mismatch. What does makeSetter(…) look like?

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

@eskimo

Here is makeSetter, but I actually fixed the issue, for now? (explanation below the code)

template<typename ArgType, typename StorageType=ArgType>

id makeSetter(__unsafe_unretained RLMProperty *const prop) {

    NSUInteger index = prop.index;

    NSString *name = prop.name;

    if (prop.isPrimary) {

        return ^(__unused RLMObjectBase *obj, __unused ArgType val) {

            @throw RLMException(@"Primary key can't be changed after an object is inserted.");

        };

    }



    return ^(__unsafe_unretained RLMObjectBase *const obj, ArgType val) {

        RLMVerifyInWriteTransaction(obj);

        RLMObservationTracker tracker(obj->_realm);

        tracker.willChange(RLMGetObservationInfo(obj->_observationInfo, obj->_row.get_key(), *obj->_info), name);

        if constexpr (std::is_same_v<ArgType, RLMObjectBase *>) {

            tracker.trackDeletions();

        }

        setValue(obj, get_property(obj, index).column_key, static_cast<StorageType>(val));

    };

}

So I actually fixed the issue and have App approved tonight. I had ATTrackingManager.requestTrackingAuthorization in App Delegate which appears to not be a place where you need to use it so I moved it to first viewcontroller. I uploaded it to App review and it got approved. I actually not sure if this was the problem as I told in original post previous version of the app had same code and was approved with working ATTrackingManager.requestTrackingAuthorization in App Delegate (and this function perfectly worked as well). I had no crashes anywhere as well so not sure if this me being lucky this time or ATTrackingManager.requestTrackingAuthorization can cause some deadblock or thread clash randomly with Realm. Maybe you have some insight on why that might happen so people with same problem can find the answer here? Anyway, thank you very much for your help I am very much appreciate it! Please have a wonderful day!

App Crash only on App Review
 
 
Q