首页 > 解决方案 > 将 RxSwift.Observable 的“compactMap”从闭包重构为函数后的内存泄漏

问题描述

我发现我的代码中可能存在泄漏,因为单元测试测试是否在以下位置调用了依赖项deinit

func testDeinit_ShouldStopMinutesTicker() throws {
    let minutesTicker = MockMinutesTicker(elapsedTicksAfterStart: [(), (), ()])
    var viewModel: AppointmentViewModel? = createAppointmentViewModel(minutesTicker: minutesTicker)
    viewModel = nil
    
    XCTAssertTrue(minutesTicker.isStopCalled)
}

这个测试通常是绿色的。但是当我重构这个时:

func selectAppointment(index: Int) {
    selectedCellParamRelay.accept(index)
}

private func setupCellParamSelection() {
    selectedCellParamRelay
        .withLatestFrom(sortedCellParams) { ($0, $1) }
        .compactMap { [weak self] index, cellParams in
            guard let `self` = self,
                  let selectedParam = cellParams[safe: index],
                  self.isUpcomingAppointment(selectedParam) else { return nil }
            
            return selectedParam
            
        }
        .bind(to: upcomingCellParamRelay)
        .disposed(by: disposeBag)
}

进入这个:

func selectAppointment(index: Int) {
    selectedCellParamRelay.accept(index)
}

private func setupCellParamSelection() {
    selectedCellParamRelay
        .withLatestFrom(sortedCellParams) { ($0, $1) }
        .compactMap(selectAppointment(index:from:))
        .bind(to: upcomingCellParamRelay)
        .disposed(by: disposeBag)
}

private func selectAppointment(
    index: Int,
    from cellParams: [AppointmentCellParam]
) throws -> AppointmentCellParam? {
    guard let selectedParam = cellParams[safe: index],
          isUpcomingAppointment(selectedParam) else { return nil }

    return selectedParam
}

private func isUpcomingAppointment(_ appointment: AppointmentCellParam) -> Bool {
    return appointment.status != .missed && appointment.status != .finished
}

它变成红色并且deinit根本不被调用。

setupCellParamSelection正在调用 func以init设置事件处理程序以按索引选择任何约会单元格。这sortedCellParams是一个由依赖项发出的中继,该依赖项又会从后端获取值。

你能帮我弄清楚第二个代码出了什么问题吗?

谢谢。

标签: iosswiftmemory-managementmemory-leaksrx-swift

解决方案


是的,因为即使函数不需要 self 也.compactMap(selectAppointment(index:from:))需要保持self才能调用。selectAppointment

这里的解决方案是移动isUpcomingAppointment(_:)selectAppointment(index:from:)类之外或作为类中的静态函数。


推荐阅读