You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何通过NumberFormatter以辅币单位显示SKProduct本地化小额单价?

How to Format Localized Unit Prices for Consumable Bundles with NumberFormatter

Absolutely! You can pull this off with NumberFormatter—it just takes a bit of targeted configuration to handle both localized currency formatting and the switch to sub-unit display when the unit price is less than one main currency unit. Let me break down exactly how to implement this for your SKProduct bundles.

Step 1: Calculate the Unit Price First

First, we need to compute the individual unit price by dividing the SKProduct's total price by the number of items in the bundle. Using NSDecimalNumber here is crucial to avoid floating-point precision errors with currency values.

func calculateUnitPrice(for product: SKProduct, bundleItemCount: Int) -> NSDecimalNumber {
    guard bundleItemCount > 0 else { return product.price }
    return product.price.dividing(by: NSDecimalNumber(value: bundleItemCount))
}

Step 2: Configure NumberFormatter for Localized Display

Next, we'll set up a NumberFormatter that uses the product's priceLocale (critical for matching the user's regional currency preferences) and adds logic to switch between main currency units and sub-units (like pence or cents) when needed.

Here's the full implementation with comments explaining each part:

func formattedUnitPrice(for product: SKProduct, bundleItemCount: Int) -> String? {
    let unitPrice = calculateUnitPrice(for: product, bundleItemCount: bundleItemCount)
    let formatter = NumberFormatter()
    formatter.locale = product.priceLocale
    
    // Get the number of decimal digits used by the currency (most use 2, some like JPY use 0)
    guard let decimalDigits = formatter.locale.object(forKey: .currencyDecimalDigits) as? Int else {
        // Fallback to basic currency formatting if we can't get decimal digits
        formatter.numberStyle = .currency
        return formatter.string(from: unitPrice)
    }
    
    let mainUnitToSubUnitRatio = NSDecimalNumber(decimal: pow(10, decimalDigits))
    let isUnitPriceLessThanMainUnit = unitPrice.compare(NSDecimalNumber.one) == .orderedAscending
    
    if isUnitPriceLessThanMainUnit {
        // Convert the unit price to an integer sub-unit amount (e.g., 0.99 GBP → 99 pence)
        guard let subUnitAmount = unitPrice.multiplying(by: mainUnitToSubUnitRatio).integerValue as NSNumber? else {
            return formatter.string(from: unitPrice)
        }
        
        // Map common currency codes to their sub-unit symbols for accuracy
        let subCurrencySymbols: [String: String] = [
            "GBP": "p",
            "USD": "¢",
            "EUR": "¢",
            "CAD": "¢",
            "AUD": "¢",
            // Add more currencies as needed for your app
        ]
        
        // Use the matching sub-unit symbol, or fall back to a reasonable default
        if let currencyCode = formatter.locale.currencyCode, let subSymbol = subCurrencySymbols[currencyCode] {
            return "\(subUnitAmount)\(subSymbol)"
        } else {
            // Fallback for less common currencies: append lowercase main symbol or just the number
            return "\(subUnitAmount)\(formatter.currencySymbol?.lowercased() ?? "")"
        }
    } else {
        // For prices ≥ 1 main unit, use standard localized currency formatting
        formatter.numberStyle = .currency
        return formatter.string(from: unitPrice)
    }
}

Key Notes & Edge Cases

  • Precision Safety: Using NSDecimalNumber ensures we don't get rounding errors that come with floating-point types like Double when dividing currency values.
  • Locale Compatibility: By using the SKProduct's priceLocale, we automatically align with the user's regional settings (e.g., decimal separators, currency symbols).
  • Zero-Decimal Currencies: For currencies like Japanese Yen (JPY) that don't use sub-units, the logic will skip the sub-unit check and always use standard currency formatting (since you can't have a price less than 1 JPY for a valid SKProduct).
  • Customization: The subCurrencySymbols dictionary can be extended to cover all currencies your app supports, ensuring the most accurate sub-unit symbols for each region.

Example Results

  • For a £9.99 bundle of 10 items (UK locale): Returns 99p
  • For a $9.99 bundle of 10 items (US locale): Returns 99¢
  • For a $5.00 bundle of 4 items (US locale): Returns $1.25

内容的提问来源于stack exchange,提问作者Ryan Brodie

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.20 10:13:21