Skip to content

Commit

Permalink
Fix brave/brave-ios#8160: User asset duplication caused by a new iOS1…
Browse files Browse the repository at this point in the history
…7 memory leaks (brave/brave-ios#8174)
  • Loading branch information
nuo-xu authored Oct 5, 2023
1 parent 3802b2e commit 73d0f28
Show file tree
Hide file tree
Showing 32 changed files with 1,285 additions and 1,236 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -162,18 +162,23 @@ extension BrowserViewController {
let walletService = BraveWallet.ServiceFactory.get(privateMode: isPrivateMode)
let rpcService = BraveWallet.JsonRpcServiceFactory.get(privateMode: isPrivateMode)

var keyringStore: KeyringStore?
if let keyringService = keyringService,
let walletService = walletService,
let rpcService = rpcService {
keyringStore = KeyringStore(
keyringService: keyringService,
walletService: walletService,
rpcService: rpcService
)
var keyringStore: KeyringStore? = walletStore?.keyringStore
if keyringStore == nil {
if let keyringService = keyringService,
let walletService = walletService,
let rpcService = rpcService {
keyringStore = KeyringStore(
keyringService: keyringService,
walletService: walletService,
rpcService: rpcService
)
}
}

let cryptoStore = CryptoStore.from(ipfsApi: braveCore.ipfsAPI, privateMode: isPrivateMode)
var cryptoStore: CryptoStore? = walletStore?.cryptoStore
if cryptoStore == nil {
cryptoStore = CryptoStore.from(ipfsApi: braveCore.ipfsAPI, privateMode: isPrivateMode)
}

let vc = SettingsViewController(
profile: self.profile,
Expand Down
8 changes: 8 additions & 0 deletions Sources/Brave/Frontend/Settings/SettingsViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,11 @@ class SettingsViewController: TableViewController {

super.init(style: .insetGrouped)
}

deinit {
keyringStore?.tearDown()
cryptoStore?.tearDown()
}

@available(*, unavailable)
required init?(coder aDecoder: NSCoder) {
Expand Down Expand Up @@ -841,6 +846,9 @@ class SettingsViewController: TableViewController {
Row(
text: Strings.Wallet.web3,
selection: { [unowned self] in
// iOS17 memory leak issue #8160
keyringStore?.setupObservers()
cryptoStore?.setupObservers()
let web3SettingsView = Web3SettingsView(
settingsStore: settingsStore,
networkStore: cryptoStore?.networkStore,
Expand Down
3 changes: 3 additions & 0 deletions Sources/BraveWallet/Crypto/CryptoView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,9 @@ public struct CryptoView: View {
),
networkStore: store.networkStore
)
.onDisappear {
store.closeAccountActivityStore(for: walletStore.keyringStore.selectedAccount)
}
.toolbar {
dismissButtonToolbarContents
}
Expand Down
166 changes: 60 additions & 106 deletions Sources/BraveWallet/Crypto/Stores/AccountActivityStore.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
import Foundation
import BraveCore

class AccountActivityStore: ObservableObject {
class AccountActivityStore: ObservableObject, WalletObserverStore {
/// If we want to observe selected account changes (ex. in `WalletPanelView`).
/// In some cases, we do not want to update the account displayed when the
/// selected account changes (ex. when removing an account).
Expand Down Expand Up @@ -37,7 +37,16 @@ class AccountActivityStore: ObservableObject {
/// Cache for storing `BlockchainToken`s that are not in user assets or our token registry.
/// This could occur with a dapp creating a transaction.
private var tokenInfoCache: [String: BraveWallet.BlockchainToken] = [:]


private var keyringServiceObserver: KeyringServiceObserver?
private var rpcServiceObserver: JsonRpcServiceObserver?
private var txServiceObserver: TxServiceObserver?
private var walletServiceObserver: WalletServiceObserver?

var isObserving: Bool {
keyringServiceObserver != nil && rpcServiceObserver != nil && txServiceObserver != nil && walletServiceObserver != nil
}

init(
account: BraveWallet.AccountInfo,
observeAccountUpdates: Bool,
Expand All @@ -63,15 +72,60 @@ class AccountActivityStore: ObservableObject {
self.ipfsApi = ipfsApi
self.assetManager = userAssetManager

self.keyringService.add(self)
self.rpcService.add(self)
self.txService.add(self)
self.walletService.add(self)
self.setupObservers()

walletService.defaultBaseCurrency { [self] currencyCode in
self.currencyCode = currencyCode
}
}

func tearDown() {
keyringServiceObserver = nil
rpcServiceObserver = nil
txServiceObserver = nil
walletServiceObserver = nil
}

func setupObservers() {
guard !isObserving else { return }
self.keyringServiceObserver = KeyringServiceObserver(
keyringService: keyringService,
_selectedWalletAccountChanged: { [weak self] account in
guard let self, self.observeAccountUpdates else { return }
self.account = account
self.update()
},
_selectedDappAccountChanged: { [weak self] _, account in
guard let self, self.observeAccountUpdates, let account else { return }
self.account = account
self.update()
}
)
self.rpcServiceObserver = JsonRpcServiceObserver(
rpcService: rpcService,
_chainChangedEvent: { [weak self] _, _, _ in
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
// Handle small gap between chain changing and txController having the correct chain Id
self?.update()
}
}
)
self.txServiceObserver = TxServiceObserver(
txService: txService,
_onNewUnapprovedTx: { [weak self] _ in
self?.update()
},
_onTransactionStatusChanged: { [weak self] _ in
self?.update()
}
)
self.walletServiceObserver = WalletServiceObserver(
walletService: walletService,
_onDefaultBaseCurrencyChanged: { [weak self] currency in
self?.currencyCode = currency
}
)
}

func update() {
Task { @MainActor in
Expand Down Expand Up @@ -273,103 +327,3 @@ class AccountActivityStore: ObservableObject {
}
#endif
}

extension AccountActivityStore: BraveWalletKeyringServiceObserver {
func keyringCreated(_ keyringId: BraveWallet.KeyringId) {
}

func keyringRestored(_ keyringId: BraveWallet.KeyringId) {
}

func keyringReset() {
}

func locked() {
}

func unlocked() {
}

func backedUp() {
}

func accountsChanged() {
}

func autoLockMinutesChanged() {
}

func selectedWalletAccountChanged(_ account: BraveWallet.AccountInfo) {
guard observeAccountUpdates else { return }
self.account = account
update()
}

func selectedDappAccountChanged(_ coin: BraveWallet.CoinType, account: BraveWallet.AccountInfo?) {
guard observeAccountUpdates, let account else { return }
self.account = account
update()
}

func accountsAdded(_ addedAccounts: [BraveWallet.AccountInfo]) {
}
}

extension AccountActivityStore: BraveWalletJsonRpcServiceObserver {
func chainChangedEvent(_ chainId: String, coin: BraveWallet.CoinType, origin: URLOrigin?) {
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
// Handle small gap between chain changing and txController having the correct chain Id
self.update()
}
}
func onAddEthereumChainRequestCompleted(_ chainId: String, error: String) {
}
func onIsEip1559Changed(_ chainId: String, isEip1559: Bool) {
}
}

extension AccountActivityStore: BraveWalletTxServiceObserver {
func onNewUnapprovedTx(_ txInfo: BraveWallet.TransactionInfo) {
update()
}
func onTransactionStatusChanged(_ txInfo: BraveWallet.TransactionInfo) {
update()
}
func onUnapprovedTxUpdated(_ txInfo: BraveWallet.TransactionInfo) {
}
func onTxServiceReset() {
}
}

extension AccountActivityStore: BraveWalletBraveWalletServiceObserver {
public func onActiveOriginChanged(_ originInfo: BraveWallet.OriginInfo) {
}

public func onDefaultWalletChanged(_ wallet: BraveWallet.DefaultWallet) {
}

public func onDefaultBaseCurrencyChanged(_ currency: String) {
currencyCode = currency
}

public func onDefaultBaseCryptocurrencyChanged(_ cryptocurrency: String) {
}

public func onNetworkListChanged() {
}

func onDefaultEthereumWalletChanged(_ wallet: BraveWallet.DefaultWallet) {
}

func onDefaultSolanaWalletChanged(_ wallet: BraveWallet.DefaultWallet) {
}

public func onDiscoverAssetsStarted() {
}

func onDiscoverAssetsCompleted(_ discoveredAssets: [BraveWallet.BlockchainToken]) {
}

func onResetWallet() {
}
}
Loading

0 comments on commit 73d0f28

Please sign in to comment.