Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Disable asserts in release builds when using Swift Package Manager #1061

Merged
merged 1 commit into from
Jan 13, 2022

Conversation

rcancro
Copy link

@rcancro rcancro commented Dec 11, 2021

When using Swift Package Manager to integrate Purchases into an app, Xcode does not automatically set NS_BLOCK_ASSERTIONS to 1 when building the package in release. This means that any NSAsserts that are hit in release cause crashes. This appears to only be an issue with ObjC packages.

The change I've made is to Package.swift to set NS_BLOCK_ASSERTIONS to 1 when building in release.

(Note: I didn't actually hit an assert in this Purchases, but the possibility is there)

I haven't added unit tests as I can't think of a way to do that using SPM. I did, however, point to your branch of 3.13.1 and change a configure method to look like:

+ (instancetype)configureWithAPIKey:(NSString *)APIKey appUserID:(nullable NSString *)appUserID {
    NSAssert(0, @"");
    return [self configureWithAPIKey:APIKey appUserID:appUserID observerMode:false];
}

When building in release and pointing to your 3.13.1 branch, this causes a crash. I think change SPM to point to my fork with the change in Package.swift and the assert no longer caused a crash.

@aboedo
Copy link
Member

aboedo commented Dec 13, 2021

Hi @rcancro! Thanks for reporting!

We try to be extremely conservative with NSAssert, where the only assertions are done for situations that would cause an irrecoverable internal inconsistency, only recoverable by a restart. An equivalent of FatalErrors for Swift.

Have you hit any of them while running the app?

Note: we're working on a v4 of the SDK, built entirely in Swift, that handles these a bit differently. This is currently in beta, though.

@NachoSoto
Copy link
Contributor

I don't love disabling assertions, but I suppose this change makes SPM consistent with the project.

@taquitos
Copy link
Contributor

I think given that we're very close to releasing RCv4, we should audit fatalError to ensure we only have that for cases where it truly is irrecoverable.

As for updating RCv3 for setting NS_BLOCK_ASSERTIONS to 1, I think that's too big of a change in behavior too close to RCv4 release. By changing the behavior for when the SDK willfully crashes, that means developers might need to inspect more things to ensure consistency, which, might not be easily possible for things that aren't explicitly public. So by blocking assertions we could be silently enabling a class of internal consistency bugs that are super hard to track down 😬

Of course, that is worst case scenario, but IMO I'd prefer to have the SDK crash right now instead of having the potential to silently do the wrong thing.

We're going to continue to examine how we willfully crash, though. This is really good feedback.

@rcancro
Copy link
Author

rcancro commented Dec 14, 2021

I did notice there are very few places where you use NSAssert in your SDK, and I haven't hit any of them. But is your intention to crash the app when one of these is hit? If you really are using NSAssert like fatalError(), then I think the more Objective-C way to do this is to raise an exception.

IMO I'd prefer to have the SDK crash right now instead of having the potential to silently do the wrong thing.

Actually, right now it appears that asserts are disabled in release for Cocoapods. If leaving assertions on in release is your desired behavior, then you need to add that to the Podspec I believe. Or if you turn asserts off in SPM it will make both methods of installing Purchases consistent.

Screen Shot 2021-12-13 at 5 23 08 PM

@taquitos
Copy link
Contributor

Yeah, great point and I didn't realize we had different configs for SPM/Pods, whoops. I'll chat with the team about this. We should, at least, be consistent!

@@ -26,7 +26,9 @@ func resolveTargets() -> [Target] {
exclude: [infoPlist],
sources: ["Purchases"],
publicHeadersPath: "Purchases/Public",
cSettings: objcSources.map { CSetting.headerSearchPath($0) }
cSettings: objcSources.map { CSetting.headerSearchPath($0) } + [
.define("NS_BLOCK_ASSERTIONS", to: "1", .when(configuration: .release))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm in favor of this to have consistency across the different types of integration, but I'll let the team chime in.
If we merge this, could you add a comment linking to https://forums.swift.org/t/assertions-in-swift-packages/42692 for future reference?

Copy link
Contributor

@taquitos taquitos left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I need to do some research before I can 👍

@aboedo
Copy link
Member

aboedo commented Jan 11, 2022

@taquitos any updates here?

@taquitos
Copy link
Contributor

taquitos commented Jan 12, 2022

I'm ok with this. That being said, we're about to launch RCv4, so we'd want to merge this in a new hotfix branch for v3.

@aboedo
Copy link
Member

aboedo commented Jan 13, 2022

@rcancro thanks for the PR, explanation and patience! I'm merging this now and making a release

@aboedo aboedo merged commit dc7dd22 into RevenueCat:release/3.13.1 Jan 13, 2022
@aboedo aboedo mentioned this pull request Jan 13, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants