Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion Virtusize/Sources/Models/VirtusizeServerProduct.swift
Original file line number Diff line number Diff line change
Expand Up @@ -115,11 +115,15 @@ public class VirtusizeServerProduct: Codable {

/// Gets the InPage recommendation text based on the user and store product info
func getRecommendationText(
_ i18nLocalization: VirtusizeI18nLocalization,
_ i18nLocalization: VirtusizeI18nLocalization?,
_ sizeComparisonRecommendedSize: SizeComparisonRecommendedSize?,
_ bodyProfileRecommendedSizeName: String?,
_ trimType: VirtusizeI18nLocalization.TrimType = VirtusizeI18nLocalization.TrimType.ONELINE
) -> String {
guard let i18nLocalization = i18nLocalization else {
return Localization.shared.localize("inpage_default_accessory_text")
}

var text = i18nLocalization.getBodyDataEmptyText()
if isAccessory() {
text = accessoryText(i18nLocalization, sizeComparisonRecommendedSize)
Expand Down
2 changes: 1 addition & 1 deletion Virtusize/Sources/UI/VirtusizeInPageMini.swift
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ public class VirtusizeInPageMini: VirtusizeInPageView {
inPageMiniMessageLabel.attributedText = NSAttributedString(
string:
sizeRecData.serverProduct.getRecommendationText(
VirtusizeRepository.shared.i18nLocalization!,
VirtusizeRepository.shared.i18nLocalization,
sizeComparisonRecommendedSize,
bodyProfileRecommendedSize?.getSizeName,
VirtusizeI18nLocalization.TrimType.ONELINE
Expand Down
48 changes: 29 additions & 19 deletions Virtusize/Sources/Virtusize.swift
Original file line number Diff line number Diff line change
Expand Up @@ -63,24 +63,20 @@ public class Virtusize {

internal static let virtusizeEventHandler = DefaultEventHandler()

internal static let dispatchQueue = DispatchQueue(label: "com.virtusize.default-queue")
/// Task to track current product load operation for cancellation
private static var loadProductTask: Task<Void, Never>?
private static let loadProductTaskLock = NSLock()

internal typealias SizeRecommendationData = ( // swiftlint:disable:this large_tuple
serverProduct: VirtusizeServerProduct,
sizeComparisonRecommendedSize: SizeComparisonRecommendedSize?,
bodyProfileRecommendedSize: BodyProfileRecommendedSize?
)

/// The private property for updating the size recommendation data for InPage views
private static var _sizeRecData: SizeRecommendationData?
/// The property to be set to updating the size recommendation data for InPage views.
internal static var sizeRecData: SizeRecommendationData? {
get {
return _sizeRecData
}
set {
_sizeRecData = newValue
if let sizeRecData = _sizeRecData {
didSet {
if let sizeRecData = sizeRecData {
DispatchQueue.main.async {
NotificationCenter.default.post(
name: .sizeRecommendationData,
Expand All @@ -94,16 +90,10 @@ public class Virtusize {

internal typealias InPageError = (hasError: Bool, externalProductId: String)

/// The property to be set to show the InPage error screen with the associated external product ID
private static var _inPageError: InPageError?
/// The property to be set to show the InPage error screen with the associated external product ID
internal static var inPageError: InPageError? {
get {
return _inPageError
}
set {
_inPageError = newValue
if let inPageError = _inPageError {
didSet {
if let inPageError = inPageError {
DispatchQueue.main.async {
NotificationCenter.default.post(
name: .inPageError,
Expand All @@ -119,15 +109,26 @@ public class Virtusize {
// MARK: - Methods
/// A function for clients to populate the Virtusize views by loading a product
public class func load(product: VirtusizeProduct) {
Task {
// Cancel previous load task if it exists
loadProductTaskLock.lock()
loadProductTask?.cancel()

// Create new task
let task = Task {
// Check if cancelled early
guard !Task.isCancelled else { return }

let productWithPDCData = await virtusizeRepository.checkProductValidity(product: product)

guard !Task.isCancelled else { return }
guard let productWithPDCData = productWithPDCData else {
inPageError = (true, product.externalId)
return
}

await virtusizeRepository.updateUserSession()

guard !Task.isCancelled else { return }
await MainActor.run {
NotificationCenter.default.post(
name: .productCheckData,
Expand All @@ -141,6 +142,7 @@ public class Virtusize {
productId: productWithPDCData.productCheckData?.productDataId
)

guard !Task.isCancelled else { return }
guard let serverProduct = serverProduct else {
inPageError = (true, product.externalId)
return
Expand All @@ -154,9 +156,17 @@ public class Virtusize {
)
}

guard !Task.isCancelled else { return }
await virtusizeRepository.fetchDataForInPageRecommendation(storeProduct: serverProduct)
virtusizeRepository.updateInPageRecommendation(product: serverProduct)

guard !Task.isCancelled else { return }
await MainActor.run {
virtusizeRepository.updateInPageRecommendation(product: serverProduct)
}
}

loadProductTask = task
loadProductTaskLock.unlock()
}

/// Sets up the VirtusizeView and adds it to `virtusizeViews`
Expand Down
38 changes: 5 additions & 33 deletions Virtusize/Sources/VirtusizeRepository.swift
Original file line number Diff line number Diff line change
Expand Up @@ -45,44 +45,16 @@ internal class VirtusizeRepository: NSObject { // swiftlint:disable:this type_bo
private var bodyProfileRecommendedSize: BodyProfileRecommendedSize?
private var hasSessionBodyMeasurement: Bool = false

private var _store: VirtusizeStore?
private let storeLock = NSLock()
private var store: VirtusizeStore? {
get {
storeLock.lock()
defer { storeLock.unlock() }
return _store
}
set {
storeLock.lock()
defer { storeLock.unlock() }
_store = newValue
}
}
private var store: VirtusizeStore?
private var shouldReloadStoreI18n: Bool = true

/// A set to cache the store product information of all the visited products
private var _serverStoreProductSet: Set<VirtusizeServerProduct> = []
private let productSetLock = NSLock()

internal var serverStoreProductSet: Set<VirtusizeServerProduct> {
get {
productSetLock.lock()
defer { productSetLock.unlock() }
return _serverStoreProductSet
}
set {
productSetLock.lock()
defer { productSetLock.unlock() }
_serverStoreProductSet = newValue
}
}
/// Note: No lock needed - protected by task cancellation in Virtusize.load()
internal var serverStoreProductSet: Set<VirtusizeServerProduct> = []
Copy link
Contributor

Choose a reason for hiding this comment

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

Can what is the value if failure? can we also declare this as weak link?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@michellequibido-virtusize VirtusizeRepository.swift is a singleton, so all properties live inside during whole app lifecycle. No need to add weak for memory management.

What about value if failure it depends. Every time a product is loaded, it will be placed to serverStoreProductSet, so either it will be empty or the product will be pre-cached by the previous request.


/// Thread-safe insert into serverStoreProductSet
/// Insert into serverStoreProductSet
private func insertIntoProductSet(_ product: VirtusizeServerProduct) {
productSetLock.lock()
defer { productSetLock.unlock() }
_serverStoreProductSet.insert(product)
serverStoreProductSet.insert(product)
}

/// Checks if the product in `VirtusizeProduct` is valid and post notifications
Expand Down