Crash in CocoaPods Zendesk (iOS) | Community
Skip to main content

Crash in CocoaPods Zendesk (iOS)

  • April 16, 2025
  • 2 replies
  • 0 views

stas

Subject: Crash on iOS when using SupportProvidersSDK 9.0.0

Body:

Hello Zendesk Support,

I’m a developer integrating the Zendesk SDKs into our iOS application, and we’ve encountered a crash that we’d like your assistance with.

📱 Environment:

  • SDK versions:
    • ZendeskSupportProvidersSDK ~> 9.0.0
    • ZendeskSupportSDK ~> 9.0.0
    • ZendeskChatSDK ~> 5.0.5
  • Device: iPhone 14 Plus
  • iOS version: 18.3.2
  • App version: 2024.10.0 (572)
  • Jailbroken: No

💥 Crash details:

The crash occurs on the main thread and seems to be related to ZDKAPIDispatcher or the internal memory handling within ZendeskCoreSDK.

 

          Crashed: com.apple.main-thread
0  ZendeskCoreSDK                 0x1d688 __swift_memcpy48_8 + 4592
1  SupportProvidersSDK            0x26218 block_destroy_helper + 12452
2  SupportProvidersSDK            0x257e8 block_destroy_helper + 9844
3  SupportProvidersSDK            0x142f0 -[ZDKAPIDispatcher executeRequestNoBlock:onSuccess:onError:] + 208
4  SupportProvidersSDK            0x14540 -[ZDKAPIDispatcher executeRequest:onSuccess:onError:] + 100
5  SupportProvidersSDK            0xe5cc __74-[ZDKRequestProvider getAnonymousRequestsWithTokens:byStatus:withCallack:]_block_invoke_2 + 360
6  SupportProvidersSDK            0x24f68 block_destroy_helper + 7668
7  ZendeskCoreSDK                 0x4c50c __swift_destroy_boxed_opaque_existential_1Tm + 8916
8  ZendeskCoreSDK                 0x4cc2c __swift_destroy_boxed_opaque_existential_1Tm + 10740
9  ZendeskCoreSDK                 0x159c8 __swift_memcpy3_1 + 3244
10 ZendeskCoreSDK                 0x47044 objectdestroy.2Tm + 4712
11 ZendeskCoreSDK                 0x159f0 __swift_memcpy3_1 + 3284
12 libdispatch.dylib              0x2248 _dispatch_call_block_and_release + 32
13 libdispatch.dylib              0x3fa8 _dispatch_client_callout + 20
14 libdispatch.dylib              0x12a34 _dispatch_main_queue_drain + 984
15 libdispatch.dylib              0x1264c _dispatch_main_queue_callback_4CF + 44
16 CoreFoundation                 0x79bcc __CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__ + 16
17 CoreFoundation                 0x761c0 __CFRunLoopRun + 1996
18 CoreFoundation                 0xc8284 CFRunLoopRunSpecific + 588
19 GraphicsServices               0x14c0 GSEventRunModal + 164
20 UIKitCore                      0x3ee674 -[UIApplication _run] + 816
21 UIKitCore                      0x14e88 UIApplicationMain + 340
22 Rocken-int                     0xef4184 main + 16 (AppDelegate.swift:16)
23 ???                            0x1af591de8 (Missing)
       

 

We are unsure what might be triggering this crash internally, as we’re using the SDK as documented. Could you help us investigate this issue?

Please let us know if you need any more information (such as logs or sample project) — we’d be happy to provide it.

Thanks in advance for your help!

Best regards,
Stanislav

2 replies

Greg29
  • April 17, 2025

Hi Stas!

 

Sorry to hear that you're dealing with this and I'd love to try and help! I don't have any immediate ideas based on what you've shared thus far, but we do have a really good article that explains the information that we'll need to troubleshoot this further. Feel free to exclude anything that you've already provided, the big thing that we would want is going to be replication in one of our sample apps. 

 

Let me know how that goes and we'll see how we can help!


stas
  • Author
  • April 29, 2025

additional code when can help for resolve this proble,

import Foundation

import SupportProvidersSDK

import ZendeskCoreSDK

import AVFoundation

import Combine

 

protocol ZendeskServiceProtocol {

    func getCountUnreadTickets(completion: @escaping Closure<Result<Int, Error>>)

}

 

final class ZendeskService: Service, ZendeskServiceProtocol {

    lazy var repository: ZendeskRepository = repositoryFactory.makeZendeskRepository()

 

    static let shared = ZendeskService()

 

    private var requestProvider = ZDKRequestProvider()

    private var uploadProvider = ZDKUploadProvider()

    private var helpProvider = ZDKHelpCenterProvider()

    private var ticketFormSubject: PassthroughSubject<TicketFormResponseModel, Error>?

 

    static func initialize(token: String = "") {

         let appId = "Hidden” 

         let clientId = "Hidden” 

         let zendeskUrl = "Hidden” 

     

        Zendesk.initialize(appId: appId,

                           clientId: clientId,

                           zendeskUrl: zendeskUrl)

 

        let identity = Identity.createJwt(token: token)

        Zendesk.instance?.setIdentity(identity)

        guard let zendesk = Zendesk.instance else { return }

        Support.initialize(withZendesk: zendesk)

        Self.setLanguageCode()

    }

 

    static func setTestMode(isTestMode: Bool = true, repositoryFactory: RepositoryFactory) {

        shared.isTestMode = isTestMode

        shared.repositoryFactory = repositoryFactory

    }

 

    static func setLanguageCode() {

        guard let support = Support.instance else { return }

        support.helpCenterLocaleOverride = "en-us"

    }

 

    func getAllTickets(completion: @escaping (Result<[TicketModel], Error>) -> Void) {

        requestProvider.getAllRequests { [weak self] agents, error in

            guard error == nil else {

                completion(.failure(error!))

                return

            }

 

            self?.requestProvider.getUpdatesForDevice { updates in

                guard let agents = agents else {

                    let error = NSError("Agents == nil")

                    completion(.failure(error))

                    return

                }

 

                var tickets: [TicketModel] = []

                tickets = agents.requests.compactMap {

                    TicketModel(request: $0,

                                supportUsers: agents.commentingAgents)

                }

 

                tickets.enumerated().forEach { index, ticket in

                    let update = updates?.requestUpdates.first { $0.key == ticket.id }

                    tickets[index].unreadCount = update?.value ?? 0

                }

                completion(.success(tickets))

            }

        }

    }

 

    func getCountUnreadTickets(completion: @escaping (Result<Int, Error>) -> Void) {

        guard !isTestMode else {

            completion(.success(0))

            return

        }

        getAllTickets { result in

            switch result {

            case .success(let tickets):

                let sum = tickets.compactMap { $0.unreadCount }.reduce(0, +)

                completion(.success(sum))

            case .failure(let error): completion(.failure(error))

            }

        }

    }

 

    func readAllTickets(ticket: TicketModel) {

        requestProvider.markRequestAsRead(ticket.id, withCommentCount: ticket.commentCount)

    }

 

    func createRequest(zendeskRequest: ZendeskRequest, completion: @escaping (Result<Void, Error>) -> Void) {

        let request = ZDKCreateRequest()

        request.subject = zendeskRequest.subject

        request.requestDescription = zendeskRequest.body

        request.tags = zendeskRequest.tags

        request.customFields = zendeskRequest.customFields.compactMap { CustomField(fieldId: $0.key, value: $0.value) }

 

        if let ticketFormId = zendeskRequest.ticketFormId {

            request.ticketFormId = ticketFormId

        }

        if let attachment = zendeskRequest.attachment {

            request.attachments = [attachment]

        }

 

        requestProvider.createRequest(request) { response, error in

            guard response != nil else {

                let error = NSError(Strings.Localizable.commonError + (error?.localizedDescription ?? ""))

                completion(.failure(error))

                return

            }

            completion(

                .success(())

            )

        }

    }

 

    func attachFile(attachedFile: AttachedFile, completion: @escaping (Result<ZDKUploadResponse, Error>) -> Void) {

        uploadProvider.uploadAttachment(attachedFile.file, withFilename: attachedFile.fileName, andContentType: attachedFile.mimeType) { response, error in

            guard let response = response else {

                let error = NSError(Strings.Localizable.commonError + (error?.localizedDescription ?? ""))

                completion(.failure(error))

                return

            }

            completion(.success(response))

        }

    }

 

    func removeFile(token: String, completion: @escaping (Result<Void, Error>) -> Void) {

        uploadProvider.deleteUpload(token) { uploadToken, error in

            guard uploadToken != nil else {

                let error = NSError(Strings.Localizable.commonError + (error?.localizedDescription ?? ""))

                completion(.failure(error))

                return

            }

            completion(

                .success(())

            )

        }

    }

 

    func getTicketForm(id: String, completion: @escaping (Result<TicketFormModel, Error>) -> Void) {

        ticketFormSubject = nil

        ticketFormSubject = PassthroughSubject()

        guard let ticketFormSubject = ticketFormSubject else { return }

        let onError: ErrorCompletion = { error in

            completion(.failure(error))

        }

 

        ticketFormSubject

            .subscribe(on: DispatchQueue.global())

            .tryMap({ result in

                guard let id = Int(id),

                     let ticketFormModel = ZendeskTicketFormMapper.map(ticketFormId: id, reponse: result) else {

                    let error = NSError("Didn't find ticket form")

                    throw error

                }

                return ticketFormModel

            })

            .receive(on: DispatchQueue.main)

            .sink(

                receiveCompletion: receiveCompletion(onError: onError),

                receiveValue: { completion(.success($0)) }

            )

            .store(in: &subscriptions)

 

        repository.getTicketForm(id: id, subject: ticketFormSubject)

    }

}

 

// MARK: Help center

extension ZendeskService {

    func getHelpCenterCategories(completion: @escaping (Result<[HelpCenterCategory], Error>) -> Void) {

        helpProvider.getCategoriesWithCallback { array, error in

            let customError = NSError(Strings.Localizable.supportNoCategoriesFound)

            if error != nil {

                completion(.failure(customError))

                return

            }

            if let categories = array as? [ZDKHelpCenterCategory] {

                let result = categories.map { HelpCenterCategory(categoryData: $0)

                }

                completion(.success(result))

            } else {

                completion(.failure(customError))

            }

        }

    }

 

    func getHelpCenterSectionsWith(categoryId: String, completion: @escaping (Result<[HelpCenterSection], Error>) -> Void) {

        helpProvider.getSectionsWithCategoryId(categoryId) { [categoryId] array, error in

            let customError = NSError(Strings.Localizable.supportCategoryLoad(categoryId))

            if error != nil {

                completion(.failure(customError))

                return

            }

            if let sections = array as? [ZDKHelpCenterSection] {

                let result = sections.map { HelpCenterSection(section: $0)

                }

                completion(.success(result))

            } else {

                completion(.failure(customError))

            }

        }

    }

 

    func getHelpCenterArticlesWith(sectionId: String, completion: @escaping (Result<[HelpCenterArticle], Error>) -> Void) {

        helpProvider.getArticlesWithSectionId(sectionId) { [sectionId] array, error in

            let customError = NSError(Strings.Localizable.supportSectionLoad(sectionId))

            if error != nil {

                completion(.failure(customError))

                return

            }

            if let articles = array as? [ZDKHelpCenterArticle] {

                let result = articles.map { HelpCenterArticle(article: $0)

                }

                completion(.success(result))

            } else {

                completion(.failure(customError))

            }

        }

    }

 

    func getHelpCenterArticleAttachments(articleId: String, completion: @escaping (Result<[HelpCenterAttachment], Error>) -> Void) {

        helpProvider.getAttachmentWithArticleId(articleId) { array, error in

            if let error = error {

                let customError = NSError(Strings.Localizable.supportAttachmentsLoad(error.localizedDescription))

                completion(.failure(customError))

                return

            }

            if let attachments = array as? [ZDKHelpCenterAttachment] {

                let result = attachments.map { HelpCenterAttachment(data: $0)

                }

                completion(.success(result))

            }

        }

    }

 

    func rateArticle(withId id: String, useful: Bool, completion: @escaping (Result<[Any], Error>) -> Void) {

        let callback: ZDKHelpCenterCallback = { array, error in

            if let error = error {

                let customError = NSError(Strings.Localizable.supportArticleVote(error.localizedDescription))

                completion(.failure(customError))

                return

            }

            if let array = array {

                completion(.success(array))

            }

        }

        if useful {

            helpProvider.upVoteArticle(withId: id, withCallback: callback)

        } else {

            helpProvider.downVoteArticle(withId: id, withCallback: callback)

        }

    }

    

    func getSearchSuggetions(searchText: String, completion: @escaping Closure<Result<[HelpCenterArticle], Error>>) {

        helpProvider.searchForArticles(usingQuery: searchText) { results, error in

            if error != nil {

                let customError = NSError(Strings.Localizable.supportNoArticlesFound)

                completion(.failure(customError))

            } else if let results = results {

                guard let articles = results as? [ZDKHelpCenterArticle] else { return }

                let mapArticles = articles.map { HelpCenterArticle(article: $0) }

                completion(.success(mapArticles))

            }

        }

    }

}