You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

自定义XCTApplicationLaunchMetric的XCTMetric方法未触发问题

自定义XCTMetric协议类未触发协议方法的问题解决

我想要获取XCTApplicationLaunchMetric上报的测量数据,于是封装了一个遵循XCTMetric协议的自定义类MyXCTApplicationLaunchMetric,内部调用XCTApplicationLaunchMetric的相关方法,代码如下:

class MyXCTApplicationLaunchMetric: NSObject, XCTMetric {
    let myLaunchMetric: XCTApplicationLaunchMetric

    init(waitUntilResponsive: Bool) {
        print(#function)
        myLaunchMetric = XCTApplicationLaunchMetric(waitUntilResponsive: waitUntilResponsive)
    }

    // XCTMetric conformance
    func willBeginMeasuring() {
        print(#function)
        myLaunchMetric.willBeginMeasuring()
    }

    // XCTMetric conformance
    func didStopMeasuring() {
        print(#function)
        myLaunchMetric.didStopMeasuring()
    }

    // XCTMetric conformance
    func reportMeasurements(from startTime: XCTPerformanceMeasurementTimestamp, to endTime: XCTPerformanceMeasurementTimestamp) throws -> [XCTPerformanceMeasurement] {
        let measurement = Measurement(value: 40, unit: .init(symbol: "M"))
        let performanceMeasurement = XCTPerformanceMeasurement(identifier: "SomeIdentifier", displayName: "SomeDisplayName", value: measurement)
        return [performanceMeasurement]
    }

    // NSObject conformance
    func copy(with zone: NSZone? = nil) -> Any {
        myLaunchMetric.copy(with: zone)
    }
}

但在测试代码中使用这个自定义指标时,只有初始化方法被调用,其他XCTMetric协议方法都没触发,测试代码如下:

final class PerformanceUITests: XCTestCase {
    func testLaunchPerformance() throws {
        if #available(macOS 10.15, iOS 13.0, tvOS 13.0, watchOS 7.0, *) {
            let options = XCTMeasureOptions()
            options.iterationCount = 1

            let launchMetric = MyXCTApplicationLaunchMetric(waitUntilResponsive: true)
            measure(metrics: [launchMetric],
                    options: options) {
                XCUIApplication().launch()
            }
        }
    }
}

问题原因

  • XCTest框架在执行measure(metrics:options:block:)时,会对传入的XCTMetric实例执行拷贝操作,而你的copy(with:)方法直接返回了内部封装的myLaunchMetric(原生XCTApplicationLaunchMetric实例),导致实际参与测量的是原生类实例,而非自定义类实例,自然不会触发自定义类中的协议方法。
  • 自定义类的copy(with:)方法未遵循NSCopying协议要求,没有返回当前自定义类的拷贝实例。

解决方案

1. 修正拷贝方法

修改copy(with:)方法,返回自定义类的拷贝实例,确保XCTest框架使用的是你的自定义类对象:

func copy(with zone: NSZone? = nil) -> Any {
    let copiedMetric = MyXCTApplicationLaunchMetric(waitUntilResponsive: myLaunchMetric.waitUntilResponsive)
    return copiedMetric
}

2. 正确获取原生测量数据(可选)

如果你需要获取XCTApplicationLaunchMetric的原生测量数据,可以在reportMeasurements方法中调用原生metric的对应方法,再对结果进行自定义处理:

func reportMeasurements(from startTime: XCTPerformanceMeasurementTimestamp, to endTime: XCTPerformanceMeasurementTimestamp) throws -> [XCTPerformanceMeasurement] {
    // 获取原生指标的测量数据
    let originalMeasurements = try myLaunchMetric.reportMeasurements(from: startTime, to: endTime)
    
    // 自定义处理逻辑:比如添加自定义测量数据
    let customMeasurement = Measurement(value: 40, unit: .init(symbol: "M"))
    let customPerformanceMeasurement = XCTPerformanceMeasurement(identifier: "SomeIdentifier", displayName: "SomeDisplayName", value: customMeasurement)
    
    // 返回原生数据+自定义数据
    return originalMeasurements + [customPerformanceMeasurement]
}

内容的提问来源于stack exchange,提问作者fingia

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.30 01:22:31