Skip to content

Commit

Permalink
Fixes the PurchasesDelegate being deallocated on iOS (#214)
Browse files Browse the repository at this point in the history
  • Loading branch information
JayShortway authored Sep 20, 2024
1 parent aa4378b commit 25c38a3
Show file tree
Hide file tree
Showing 3 changed files with 18 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,10 @@ public expect class Purchases {
/**
* The delegate is responsible for handling promotional product purchases (App Store only) and
* changes to customer information.
*
* **Note:** If your delegate is not a singleton, make sure you set this back to null when
* you're done to avoid memory leaks. For instance, if your delegate is tied to a screen, set
* this to null when the user navigates away from the screen.
*/
public var delegate: PurchasesDelegate?

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.revenuecat.purchases.kmp

import cocoapods.PurchasesHybridCommon.RCCommonFunctionality
import cocoapods.PurchasesHybridCommon.RCPurchasesDelegateProtocol
import cocoapods.PurchasesHybridCommon.RCStoreProduct
import cocoapods.PurchasesHybridCommon.configureWithAPIKey
import cocoapods.PurchasesHybridCommon.recordPurchaseForProductID
Expand Down Expand Up @@ -117,9 +118,18 @@ public actual class Purchases private constructor(private val iosPurchases: IosP
public actual val appUserID: String
get() = iosPurchases.appUserID()

/**
* Making sure we keep a strong reference to our delegate wrapper, as iosPurchases only keeps
* a weak one. This avoids the wrapper from being deallocated the first chance it gets. This
* behavior matches the Android platform behavior.
*/
private var _delegateWrapper: RCPurchasesDelegateProtocol? = null
public actual var delegate: PurchasesDelegate?
get() = iosPurchases.delegate()?.toPurchasesDelegate()
set(value) = iosPurchases.setDelegate(value?.toRcPurchasesDelegate())
set(value) {
_delegateWrapper = value.toRcPurchasesDelegate()
iosPurchases.setDelegate(_delegateWrapper)
}

public actual val isAnonymous: Boolean
get() = iosPurchases.isAnonymous()
Expand Down Expand Up @@ -340,7 +350,7 @@ public actual class Purchases private constructor(private val iosPurchases: IosP
}

public actual fun close() {
iosPurchases.setDelegate(null)
delegate = null
}

public actual fun getCustomerInfo(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ import platform.darwin.NSObject
internal fun RCPurchasesDelegateProtocol.toPurchasesDelegate(): PurchasesDelegate =
(this as PurchasesDelegateWrapper).wrapped

internal fun PurchasesDelegate.toRcPurchasesDelegate(): RCPurchasesDelegateProtocol =
PurchasesDelegateWrapper(this)
internal fun PurchasesDelegate?.toRcPurchasesDelegate(): RCPurchasesDelegateProtocol? =
this?.let { PurchasesDelegateWrapper(it) }

private class PurchasesDelegateWrapper(val wrapped: PurchasesDelegate) :
RCPurchasesDelegateProtocol,
Expand Down

0 comments on commit 25c38a3

Please sign in to comment.