ios 从设置中删除可取消项会导致应用程序崩溃

blmhpbnm  于 2023-01-06  发布在  iOS
关注(0)|答案(1)|浏览(157)

我有一个发布者pipelinePublisher,它运行各种操作的组合管道,其中一些操作向作为参数传入的statePublisher发送状态更新。pipelinePublisher在其组合管道完成时被删除:

func myFunction(_ request: MyRequest) -> PassthroughSubject<State, Never> {
    let statePublisher = PassthroughSubject<State, Never>()
    let presentationSubject = CurrentValueSubject<MyRequest, Error>(request)

    var pipelinePublisher: AnyCancellable!

    pipelinePublisher = presentationSubject
      .eraseToAnyPublisher()
      .checkSomething(returningStateTo: statePublisher)
      // a few more operators here...
      .sink(
        receiveCompletion: { [weak self] _ in
          self?.cancellables.remove(pipelinePublisher) // Crash happens here
        },
        receiveValue: { _ in }
      )

    pipelinePublisher.store(in: &cancellables)

    return statePublisher
      .receive(on: RunLoop.main)
      .eraseToAnyPublisher()
  }

然而,当我连续多次快速调用该函数时,应用程序偶尔会在self?.cancellables.remove(pipelinePublisher)行崩溃,这通常会导致两种可能的堆栈跟踪之一,第一种是:

2022-12-21 15:24:51.926131+0000 MyApp[23082:12933690] -[_NSCoreDataTaggedObjectID member:]: unrecognized selector sent to instance 0x8000000000000000
2022-12-21 15:24:51.931941+0000 MyApp[23082:12933690] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[_NSCoreDataTaggedObjectID member:]: unrecognized selector sent to instance 0x8000000000000000'
*** First throw call stack:
(
    0   CoreFoundation                      0x000000018040e7c8 __exceptionPreprocess + 172
    1   libobjc.A.dylib                     0x0000000180051144 objc_exception_throw + 56
    2   CoreFoundation                      0x000000018041d47c +[NSObject(NSObject) instanceMethodSignatureForSelector:] + 0
    3   CoreFoundation                      0x00000001804126c8 ___forwarding___ + 1308
    4   CoreFoundation                      0x0000000180414b4c _CF_forwarding_prep_0 + 92
    5   libswiftCore.dylib                  0x000000018be6ee68 $sSh8_VariantV6removeyxSgxF + 160
    6   MyApp               0x00000001026c6080 $s12MyApp0A0C17myFunctiony7Combine12AnyPublisherVyAA12StateOs5NeverOGAA19MyRequestVFyAE11SubscribersO10CompletionOy_s5Error_pGcfU_ + 440
    7   Combine                             0x000000019baa2a70 $s7Combine11SubscribersO4SinkC7receive10completionyAC10CompletionOy_q_G_tF + 364
    8   Combine                             0x000000019baa2f28 $s7Combine11SubscribersO4SinkCy_xq_GAA10SubscriberA2aGP7receive10completionyAC10CompletionOy_7FailureQzG_tFTW + 20
    9   Combine                             0x000000019bb541cc $s7Combine10PublishersO7FlatMapV5Outer33_E91C3F00A6DFAAFEA2009FAF507AE039LLC7receive10completionyAA11SubscribersO10CompletionOy_7FailureQzG_tF + 1516
    10  Combine                             0x000000019bb55328 $s7Combine10PublishersO7FlatMapV5Outer33_E91C3F00A6DFAAFEA2009FAF507AE039LLCy_xq__qd__GAA10SubscriberA2aJP7receive10completionyAA11SubscribersO10CompletionOy_7FailureQzG_tFTW + 20
    11  Combine                             0x000000019bb53474 $s7Combine10PublishersO7FlatMapV5Outer33_E91C3F00A6DFAAFEA2009FAF507AE039LLC12receiveInner10completion_yAA11SubscribersO10CompletionOy_7FailureQzG_SitF + 1668
    12  Combine                             0x000000019bb52de4 $s7Combine10PublishersO7FlatMapV5Outer33_E91C3F00A6DFAAFEA2009FAF507AE039LLC4SideV7receive10completionyAA11SubscribersO10CompletionOy_7FailureQzG_tF + 20
    13  Combine                             0x000000019bac45ec $s7Combine6FutureC7Conduit33_3AE68DE9BADC00342FC052FEBC7D3BA6LLC7fulfillyys6ResultOyxq_GF + 1056
    14  Combine                             0x000000019bac4960 $s7Combine6FutureC7Conduit33_3AE68DE9BADC00342FC052FEBC7D3BA6LLC6finish10completionyAA11SubscribersO10CompletionOy_q_G_tF + 336
    15  Combine                             0x000000019bac2de4 $s7Combine6FutureC7promise33_3AE68DE9BADC00342FC052FEBC7D3BA6LLyys6ResultOyxq_GFyAA11ConduitBaseCyxq_GXEfU0_ + 156
    16  Combine                             0x000000019bac6b28 $s7Combine6FutureC7promise33_3AE68DE9BADC00342FC052FEBC7D3BA6LLyys6ResultOyxq_GFyAA11ConduitBaseCyxq_GXEfU0_TA + 16
    17  Combine                             0x000000019bae5140 $s7Combine11ConduitListO7forEachyyyAA0B4BaseCyxq_GKXEKF + 212
    18  Combine                             0x000000019bac2bfc $s7Combine6FutureC7promise33_3AE68DE9BADC00342FC052FEBC7D3BA6LLyys6ResultOyxq_GF + 716
    19  Combine                             0x000000019bac6b08 $s7Combine6FutureCyACyxq_Gyys6ResultOyxq_GcccfcyAGcfU_TA + 20
    20  MyApp               0x0000000102541dd8 $s7Combine6FutureC12MyApps5Error_pRs_rlE9operationACyxsAE_pGxyYaKc_tcfcyys6ResultOyxsAE_pGccfU_yyYaYbcfU_TY2_ + 212
    21  MyApp               0x0000000102542705 $s7Combine6FutureC12MyApps5Error_pRs_rlE9operationACyxsAE_pGxyYaKc_tcfcyys6ResultOyxsAE_pGccfU_yyYaYbcfU_TATQ0_ + 1
    22  MyApp               0x000000010242f1a1 $sxIeghHr_xs5Error_pIegHrzo_s8SendableRzs5NeverORs_r0_lTRTQ0_ + 1
    23  MyApp               0x000000010242f749 $sxIeghHr_xs5Error_pIegHrzo_s8SendableRzs5NeverORs_r0_lTRTA.24TQ0_ + 1
    24  libswift_Concurrency.dylib          0x00000001b03bedcd _ZL23completeTaskWithClosurePN5swift12AsyncContextEPNS_10SwiftErrorE + 1
)
libc++abi: terminating with uncaught exception of type NSException

第二个在相同的位置,但有错误:*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSCFNumber member:]: unrecognized selector sent to instance 0x8000000000000000'
是什么原因导致这个问题?我试过将pipelinePublisher设置为可选,并在删除之前检查它是否存在,但它确实存在,但仍然崩溃。我无法解决这个问题,请帮助!
编辑
我使用foo方法调用myFunction(_:),该方法得到一个publisher

static func publisher(forParam: String) -> AnyPublisher<State, Never> {
    return Future {
      // Do some stuff here
      return objects
    }
    .flatMap { objects in
      let request = MyRequest(objects)
      return shared.myFunction(request)
    }
    .eraseToAnyPublisher()
  }

static func foo(
    param: String,
    handler: ((State) -> Void)? = nil
  ) {
    var cancellable: AnyCancellable!
    cancellable = publisher(forParam: param)
    .sink(
      receiveCompletion: { _ in
        self.shared.fooItems.cancellables.remove(cancellable) // sometimes crashes here too with the exact same crash!
      }, receiveValue: { state in
        handler?(state)
      }
    )

    cancellable.store(in: &shared.fooItems.cancellables)
  }

需要注意的几点:

  • Foo必须使用完成块作为API的一部分。
  • publisher(forParam:)myFunction(_:)只能从foo调用,而foo可以从许多地方调用。
  • myFunction的pipelinePublisher被一个错误取消,该错误在向foo发送状态和完成的同时抛出。
  • 状态也可以发送到foo而不需要后续完成。

正如您在上面看到的,foo在删除可取消项时有时也会得到相同的错误。

uidvcgyl

uidvcgyl1#

在我的问题的评论中,人们帮助我解决了一个可能由线程之间交互引起的争用问题。我从Set中删除了Sets,但是Sets不是线程安全的。我通过更改代码来使用Subscribers.Sink解决了这个问题:

func myFunction(_ request: MyRequest) -> PassthroughSubject<State, Never> {
    let statePublisher = PassthroughSubject<State, Never>()
    let presentationSubject = CurrentValueSubject<MyRequest, Error>(request)

    var pipelinePublisher: AnyCancellable!

    pipelinePublisher = presentationSubject
      .eraseToAnyPublisher()
      .checkSomething(returningStateTo: statePublisher)
      // a few more operators here...
      .subscribe(Subscribers.Sink(
        receiveCompletion: { _ in },
        receiveValue: { _ in }
      ))

    pipelinePublisher.store(in: &cancellables)

    return statePublisher
      .receive(on: RunLoop.main)
      .eraseToAnyPublisher()
  }

此操作修复了问题。管道返回时,合并将处理订阅和订阅服务器的清理。
这是从这里给出的答案:使用合并时,如何在网络请求后取消分配订阅

相关问题