11

インスタンスNSSoundに変換したいオブジェクトがいくつかあります。オブジェクトに関連付けられたAVAudioPlayerファイル パス ( ) がありますが、元のファイルが存在しない可能性があります。これが私がこれまでに持っているものです:NSURLNSSound

class SoundObj: NSObject {
    var path: NSURL?
    var sound: NSSound?
    var player: AVAudioPlayer
}

let aSound = SoundObj()
aSound.path = NSURL(fileURLWithPath: "file:///path/to/sound.m4a")
aSound.sound = NSSound(contentsOfURL: aSound.path)!

do {
    try aSound.player = AVAudioPlayer(contentsOfURL: aSound.path)
} catch {
    // perhaps use AVAudioPlayer(data: ...)?
}

NSSoundオブジェクトをAVAudioPlayerインスタンスに変換するにはどうすればよいですか?

4

1 に答える 1

3

NSSoundそのため、オブジェクトから URL を取得するためのパブリック インターフェイスが見つからなかったので、プライベート ヘッダーを調べて、何が見つかるかを調べました。の URL を返すプライベート インスタンス メソッドurlと. おそらく、これらはivar またはプロパティのゲッターです。_urlNSSoundNSURL

Objective-C を使用すると、これは簡単です。メソッドを新しいインターフェイスまたは拡張機能に追加するだけです。純粋な Swift の場合は少し複雑で、Objective-C プロトコルを介してアクセサーを公開する必要があります。

@objc protocol NSSoundPrivate {
    var url: NSURL? { get }
}

はインスタンス メソッドであるため、変数を使用する代わりに使用したurl方が良い結果が得られる場合があります。func url() -> NSURL?あなたのマイレージは異なる場合があります.aを使用しvarて読み取り専用プロパティの動作をエミュレートすることは、私にとってはうまくいくようです.

の拡張機能に新しい便利な初期化子を書きましたAVAudioPlayer:

extension AVAudioPlayer {
    convenience init?(sound: NSSound) throws {    
        let privateSound = unsafeBitCast(sound, NSSoundPrivate.self)    
        guard let url = privateSound.url else { return nil }
        do {
            try self.init(contentsOfURL: url)
        } catch {
            throw error
        }
    }
}

使用法:

let url = NSURL(...)    
if let sound = NSSound(contentsOfURL: url, byReference: true) {
    do {
        let player = try AVAudioPlayer(sound: sound)
        player?.play()
    } catch {
        print(error)
    }        
}

NSDataNSSound の ivar、インスタンス メソッド、およびプロパティに関連するものを見つけようとした後、初期化に使用するもののデータ部分がNSSoundクラスの実装のどこかで難読化されており、そうではないという結論に達しました。 URLのように利用できます。

于 2016-05-04T00:07:38.360 に答える