Nan
Nan

Reputation: 524

Issue with variable closure initialization issue

In my class, I have a property that is a sort of audioPlayer and I am planning to do the setup job in a closure as this:

var urlPath = Bundle.main.url(forResource: "Focus", withExtension: "mp3")!

var audioPlayer:AVAudioPlayer = { var player =  try! AVAudioPlayer.init(contentsOf: urlPath)

    return player }()

Instance member 'urlPath' cannot be used on type 'BackgroundAudio'

enter image description here

I don't quite understand what is wrong with my code? How to resolve this, thanks in advance.

Upvotes: 1

Views: 59

Answers (3)

Rob
Rob

Reputation: 437452

Correct, it's saying that it cannot use the other stored property during initialization, because it doesn't know if it is initialized or not. As The Swift Programming Language says:

If you use a closure to initialize a property, remember that the rest of the instance has not yet been initialized at the point that the closure is executed. This means that you cannot access any other property values from within your closure, even if those properties have default values. You also cannot use the implicit self property, or call any of the instance’s methods.

You can resolve this by making audioPlayer a lazy var, so the initialization is deferred until you first use it, resolving the ambiguity. E.g.

var urlPath = Bundle.main.url(forResource: "Focus", withExtension: "mp3")!
lazy var audioPlayer: AVAudioPlayer = try! AVAudioPlayer(contentsOf: self.urlPath)

Or if you don't need this URL reference elsewhere, you can just have a single constant:

let audioPlayer: AVAudioPlayer = {
    var urlPath = Bundle.main.url(forResource: "Focus", withExtension: "mp3")!
    return try! AVAudioPlayer(contentsOf: urlPath)
}()

Lots of options. The key is that you can't have a simple stored property initializing itself using another property's value. You need someway to resolve the ambiguity, such as the two above approaches.

Upvotes: 0

Lawliet
Lawliet

Reputation: 3499

There was a syntax error in your code. As audioPlayer is a computed property, you should not have =.

The following

var audioPlayer:AVAudioPlayer = { var player =  try! AVAudioPlayer.init(contentsOf: urlPath)

    return player }()

should be written as

var audioPlayer: AVAudioPlayer {
    var player = try! AVAudioPlayer(contentsOf: urlPath)
    return player
}

Upvotes: 0

KKRocks
KKRocks

Reputation: 8322

Try this :

import AudioToolbox 
 import AVFoundation

let url = Bundle.main.url(forResource: "Focus", withExtension: "mp3")!

    do {
        player = try AVAudioPlayer(contentsOf: url)
        guard let player = player else { return }

        player.prepareToPlay()
        player.play()
    } catch let error as NSError {
        print(error.description)
    }

Upvotes: 1

Related Questions