From 5e160298410b87975b194163d843d18e7360cecd Mon Sep 17 00:00:00 2001 From: Evgeny Date: Tue, 25 Nov 2025 15:49:33 +0000 Subject: [PATCH] ios: reduce memory used by iOS share extension (#6465) --- apps/ios/SimpleX SE/ShareAPI.swift | 38 +++++++++++++++++++++++++--- apps/ios/SimpleX SE/ShareModel.swift | 12 ++++----- apps/ios/SimpleXChat/ChatUtils.swift | 4 +-- 3 files changed, 42 insertions(+), 12 deletions(-) diff --git a/apps/ios/SimpleX SE/ShareAPI.swift b/apps/ios/SimpleX SE/ShareAPI.swift index 4dad9d5d15..6495d09b03 100644 --- a/apps/ios/SimpleX SE/ShareAPI.swift +++ b/apps/ios/SimpleX SE/ShareAPI.swift @@ -48,7 +48,7 @@ func apiSetEncryptLocalFiles(_ enable: Bool) throws { throw r.unexpected } -func apiGetChats(userId: User.ID) throws -> Array { +func apiGetChats(userId: User.ID) throws -> Array { let r: APIResult = sendSimpleXCmd(SEChatCommand.apiGetChats(userId: userId)) if case let .result(.apiChats(user: _, chats: chats)) = r { return chats } throw r.unexpected @@ -170,7 +170,7 @@ enum SEChatResponse: Decodable, ChatAPIResult { case activeUser(user: User) case chatStarted case chatRunning - case apiChats(user: UserRef, chats: [ChatData]) + case apiChats(user: UserRef, chats: [SEChatData]) case newChatItems(user: UserRef, chatItems: [AChatItem]) case cmdOk(user_: UserRef?) @@ -199,7 +199,7 @@ enum SEChatResponse: Decodable, ChatAPIResult { } static func fallbackResult(_ type: String, _ json: NSDictionary) -> SEChatResponse? { - if type == "apiChats", let r = parseApiChats(json) { + if type == "apiChats", let r = seParseApiChats(json) { .apiChats(user: r.user, chats: r.chats) } else { nil @@ -239,3 +239,35 @@ enum SEChatEvent: Decodable, ChatAPIResult { } } } + +public struct SEChatData: Decodable, Identifiable, Hashable, ChatLike { + public var chatInfo: ChatInfo + + public var id: ChatId { get { chatInfo.id } } + + public init(chatInfo: ChatInfo) { + self.chatInfo = chatInfo + } + + public static func invalidJSON(_ json: Data?) -> SEChatData { + SEChatData(chatInfo: .invalidJSON(json: json)) + } +} + +public func seParseApiChats(_ jResp: NSDictionary) -> (user: UserRef, chats: [SEChatData])? { + if let jApiChats = jResp["apiChats"] as? NSDictionary, + let user: UserRef = try? decodeObject(jApiChats["user"] as Any), + let jChats = jApiChats["chats"] as? NSArray { + let chats: [SEChatData] = jChats.map { jChat in + if let jChatDict = jChat as? NSDictionary, + let jChatInfo = jChatDict["chatInfo"], + let chatInfo: ChatInfo = try? decodeObject(jChatInfo) { + return SEChatData(chatInfo: chatInfo) + } + return SEChatData.invalidJSON(serializeJSON(jChat, options: .prettyPrinted)) + } + return (user, chats) + } else { + return nil + } +} diff --git a/apps/ios/SimpleX SE/ShareModel.swift b/apps/ios/SimpleX SE/ShareModel.swift index 5080cf2040..fd5c4c990f 100644 --- a/apps/ios/SimpleX SE/ShareModel.swift +++ b/apps/ios/SimpleX SE/ShareModel.swift @@ -19,11 +19,11 @@ private let MAX_DOWNSAMPLE_SIZE: Int64 = 2000 class ShareModel: ObservableObject { @Published var sharedContent: SharedContent? - @Published var chats: [ChatData] = [] + @Published var chats: [SEChatData] = [] @Published var profileImages: [ChatInfo.ID: UIImage] = [:] @Published var search = "" @Published var comment = "" - @Published var selected: ChatData? + @Published var selected: SEChatData? @Published var isLoaded = false @Published var bottomBar: BottomBar = .loadingSpinner @Published var errorAlert: ErrorAlert? @@ -60,13 +60,13 @@ class ShareModel: ObservableObject { } } - func isProhibited(_ chat: ChatData?) -> Bool { + func isProhibited(_ chat: SEChatData?) -> Bool { if let chat, let sharedContent { sharedContent.prohibited(in: chat, hasSimplexLink: hasSimplexLink) } else { false } } - var filteredChats: [ChatData] { + var filteredChats: [SEChatData] { search.isEmpty ? filterChatsToForwardTo(chats: chats) : filterChatsToForwardTo(chats: chats) @@ -253,7 +253,7 @@ class ShareModel: ObservableObject { } } - private func fetchChats() -> Result, ErrorAlert> { + private func fetchChats() -> Result, ErrorAlert> { do { guard let user = try apiGetActiveUser() else { return .failure( @@ -396,7 +396,7 @@ enum SharedContent { } } - func prohibited(in chatData: ChatData, hasSimplexLink: Bool) -> Bool { + func prohibited(in chatData: SEChatData, hasSimplexLink: Bool) -> Bool { chatData.prohibitedByPref( hasSimplexLink: hasSimplexLink, isMediaOrFileAttachment: cryptoFile != nil, diff --git a/apps/ios/SimpleXChat/ChatUtils.swift b/apps/ios/SimpleXChat/ChatUtils.swift index 98ee9cd5d4..451ac8b4ef 100644 --- a/apps/ios/SimpleXChat/ChatUtils.swift +++ b/apps/ios/SimpleXChat/ChatUtils.swift @@ -9,9 +9,7 @@ import Foundation public protocol ChatLike { - var chatInfo: ChatInfo { get} - var chatItems: [ChatItem] { get } - var chatStats: ChatStats { get } + var chatInfo: ChatInfo { get } } extension ChatLike {