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

为何我的volumeChanged函数不是公开Selector?Apple Connect上传报错

问题描述

资源验证失败(50)
应用在Payload/some/path中引用了非公开选择器:volumeChanged: (ID: 060de305-b6d2-4314-a238-c679fa85404e)

我的volumeChanged函数为何不属于公开选择器?

以下是精简后的代码(省略了UIViewControllerRepresentable的其他协议存根):

import SwiftUI
import AVFoundation
import MediaPlayer

struct VolumeEventReader<Content: View>: UIViewControllerRepresentable {
    class Coordinator: NSObject {
        var parent: VolumeEventReader
        var lastVolumeNotificationSequenceNumber: Int?
        var currentVolume = AVAudioSession.sharedInstance().outputVolume

        init(_ parent: VolumeEventReader) {
            self.parent = parent
        }

        @objc func volumeChanged(_ notification: NSNotification) {
            DispatchQueue.main.async { [self] in
                volumeControl(notification)
            }
        }

        func manageVolume(volume: Float, minVolume: Float) {
            switch volume {
            case minVolume: do {
                currentVolume = minVolume + 0.0625
            }
            case 1: do {
                currentVolume = 0.9375
            }
            default: break
            }

            parent.updateUIView(volume: volume)
            
            currentVolume = volume
        }

        func volumeControl(_ notification: NSNotification) {
            let minVolume: Float = 0.0625

            if let volume = notification.userInfo!["Volume"] as? Float {
                //avoiding duplicate events if same ID notification was generated
                if let seqN = self.lastVolumeNotificationSequenceNumber {
                    if seqN == notification.userInfo!["SequenceNumber"] as! Int {
                        // Duplicate nofification received
                    }
                    else {
                        self.lastVolumeNotificationSequenceNumber = (notification.userInfo!["SequenceNumber"] as! Int)
                        manageVolume(volume: volume, minVolume: minVolume)
                    }
                }
                else {
                    self.lastVolumeNotificationSequenceNumber = (notification.userInfo!["SequenceNumber"] as! Int)
                    manageVolume(volume: volume, minVolume: minVolume)
                }
            }
        }
    }

    func makeCoordinator() -> Coordinator {
        let coordinator = Coordinator(self)

        NotificationCenter.default.addObserver(
            coordinator,
            selector: #selector(Coordinator.volumeChanged),
            name: NSNotification.Name(rawValue: "SystemVolumeDidChange"),
            object: nil
        )

        return coordinator
    }
}
解决方案

Apple的审核扫描会把和系统私有API同名的选择器判定为非公开选择器——哪怕这个方法是你自己定义的。这里的问题就是volumeChanged:这个名称和系统内部的私有选择器重名了。

直接修改方法名就能解决:

  1. 将Coordinator类里的volumeChanged(_:)改个独特的名字,比如handleSystemVolumeChange(_:)
  2. 同步更新@objc修饰的方法名,以及addObserver里的#selector引用

修改后的关键代码:

@objc func handleSystemVolumeChange(_ notification: NSNotification) {
    DispatchQueue.main.async { [self] in
        volumeControl(notification)
    }
}

// 在makeCoordinator中更新选择器
NotificationCenter.default.addObserver(
    coordinator,
    selector: #selector(Coordinator.handleSystemVolumeChange),
    name: NSNotification.Name(rawValue: "SystemVolumeDidChange"),
    object: nil
)

额外提醒:你监听的SystemVolumeDidChange属于非公开系统通知,这次审核没触发警告,但后续可能被检测到。建议改用公开API方案监听音量变化,比如通过AVAudioSession的outputVolume结合KVO,或者使用MPVolumeView相关逻辑,避免依赖私有通知。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.21 23:44:55