Extensions based on the contents of the current textbook (adjust the volume of the UI slider sound source)
is about to be implemented.
The problem I want to solve is that I can adjust the volume after playing music (running the play() method).
When I try to adjust the volume on the slider before playing music, the error Thread1:EXC_BAD_ACCESS(code=1, address=0x48) appears and the process stops.
I spent half a day trying to solve the error, but I can't find a clue to the solution with my current
I asked you a question.
I would appreciate it if someone could let me know.
The code is reprinted below.
I will add any missing information.
import UIKit
import AVFoundation
import MediaPlayer
classViewController:UIViewController {
override func viewDidLoad(){
super.viewDidLoad()
// Do any additional setup after loading the view, typically from anib.
}
override funcdidReceiveMemoryWarning(){
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func prepareToPlay()->Bool{
return true
}
// Specifying the cymbal sound source file
let cymbalPath=Bundle.main.bundleURL.appendingPathComponent("cymbal.mp3")
// Generate a player instance for cymbals
varcymbalPlayer=AVAudioPlayer()
// Specify the guitar sound source file
let guitarPath=Bundle.main.bundleURL.appendingPathComponent("guitar.mp3")
// Generate a player instance for cymbals
varguitarPlayer=AVAudioPlayer()
// Specifying background music source files
letbackMusicPath=Bundle.main.bundleURL.appendingPathComponent("backmusic.mp3")
// Generate background music player instances
varbackMusicPlayer=AVAudioPlayer()
@ IBAction function(_sender:Any){
soundPlayer (player: & cymbalPlayer, path: cymbalPath, count:0)
}
@ IBAction funcguitar(_sender:Any){
soundPlayer(player:&guitarPlayer, path:guitarPath, count:1)
}
@ IBAction funcplay(_sender:Any){
soundPlayer(player:&backMusicPlayer, path:backMusicPath, count:-1)
}
// What to do when the stop button is tapped?
@ IBAction func stop(_sender:Any){
soundPlayer(player:&backMusicPlayer, path:backMusicPath, count:0)
backMusicPlayer.stop()
}
@IBOutlet weak var volume:UISlider!
@ IBAction func volumeController(_sender:UISlider){
backMusicPlayer.volume=volume.value
}
// Common player playback processing
fileprivate func soundPlayer(player:inoutAVAudioPlayer, path:URL, count:Int){
do{
player=try AVAudioPlayer(contentsOf:path, fileTypeHint:nil)
player.play()
} catch{
print("Error Occurred!")
}
}
}
These three lines are the worst points you can see from the code you are currently posting.
var cymbalPlayer=AVAudioPlayer()
varguitarPlayer=AVAudioPlayer()
varbackMusicPlayer=AVAudioPlayer()
Each statement is a syntax that declares instance properties and initializes it with AVAudioPlayer()
.However, the behavior of the initializer AVAudioPlayer.init()
without arguments is not mentioned at all in the Apple AVAudioPlayer
official document.
In other words, there is no guarantee that an instance created with the syntax I don't know long ago, but on iOS from at least 4-5 years ago, no matter what method you try to get an instance created with As for the fix, if you cannot create the appropriate instance when declaring the property, you should use the I don't know what kind of "textbook" you use, but if There seems to be a lot of trial and error, so the above correction may not be enough, but it should be necessary first.If there is anything you can't do with just this, please let me know in your comments.AVAudioPlayer()
will work. Apple documents may not be flattering enough, so you may have to use poorly documented features, but at least AVAudioPlayer
should not use the syntax AVAudioPlayer(/code>).
AVAudioPlayer()
, the app always crashes.Optional
type instead of forcing a strange instance.This allows the rest of the code to determine whether the value is nil
or not "before the appropriate instance is created."class ViewController:UIViewController {
// ... (no changes)
// Specifying the cymbal sound source file
let cymbalPath=Bundle.main.bundleURL.appendingPathComponent("cymbal.mp3")
// Player properties for cymbals
varcybalPlayer —AVAudioPlayer ?//<-
// Specify the guitar sound source file
let guitarPath=Bundle.main.bundleURL.appendingPathComponent("guitar.mp3")
// Player properties for cymbals
varguitarPlayer —AVAudioPlayer ?//<-
// Specifying background music source files
letbackMusicPath=Bundle.main.bundleURL.appendingPathComponent("backmusic.mp3")
// Back music player properties
varbackMusicPlayer —AVAudioPlayer ?//<-
@ IBAction function(_sender:Any){
soundPlayer (player: & cymbalPlayer, path: cymbalPath, count:0)
}
@ IBAction funcguitar(_sender:Any){
soundPlayer(player:&guitarPlayer, path:guitarPath, count:1)
}
@ IBAction funcplay(_sender:Any){
soundPlayer(player:&backMusicPlayer, path:backMusicPath, count:-1)
}
// What to do when the stop button is tapped?
@ IBAction func stop(_sender:Any){
// ↓ No need to assign a new player to stop
// soundPlayer(player:&backMusicPlayer, path:backMusicPath, count:0)
US>backMusicPlayer ?.stop()//<-
}
@IBOutlet weak var volume:UISlider!
@ IBAction func volumeController(_sender:UISlider){
backMusicPlayer ?.volume=volume.value//<-
}
// Common player playback processing
fileprivate func soundPlayer(player:inoutAVAudioPlayer?, path:URL, count:Int) {//<- `AVAudioPlayer?` instead of `AVAudioPlayer`
do{
player=try AVAudioPlayer(contentsOf:path, fileTypeHint:nil)
player?play()//<-
} catch{
print("Error Occurred!", error) // < - Throwing the error makes debugging difficult
}
}
}
AVAudioPlayer()
directly uses the syntax, but does not mention any of the above precautions, the author of the text is likely to have little experience in iOS development.
*The following expression is "Questioner has this kind of wrong understanding," but you may get the impression that the questioner has no idea.That's probably because the author of the textbook you're writing is misleading.Therefore, please read the expressions flexibly.
There are two possible misconceptions that the questioner may have:One for class AVAudioPlayer
.The other concerns Swift and object-oriented reference types.First, let's talk about a misunderstanding about the AVAudioPlayer
class.
From the name AVAudioPlayer
, isn't this class associated with the metaphor of a portable music player such as a CD deck, Walkman, and iPod touch?If you insert Beethoven's Ninth Symphony into the CD deck and press the Play button, the Ninth Symphony will be played, and if you insert Mozart's Magic Flute CD, the Magic Flute will be played.Volume is set on the CD deck, and the volume will not be restored every time you change the CD.
However, the AVAudioPlayer
instance is not like that, but one AVAudioPlayer
instance is created for one song, one voice data.
See the Class AVAudioPlayer properties url
and data
sections.
url
var url:URL?{get}
(data
as well.) {get}
means read-only and non-writeable properties ({getset}
if writable)
In other words, if you replace the CD (if you change the URL or file path), it doesn't mean that another song will be played.Once you generate an instance by specifying the URL in Init(contentsOfurl:URL), you cannot change it later.
Based on the code provided, I do not believe that Swift and object-oriented instance references are correctly understood.It's a good opportunity, so let's study Swift's "class reference type."
First, Swift limits reference objects to classes only.Other structures, Enumeration, etc. are value types, not reference types.
So, what is a reference type? First, run the following code in Playground in Xcode.
//Defining Class Hoge
class Hoge {
var name —String
var volume —Float=0
init(name:String){
self.name = name
}
}
// Instance class Hoge.
var hoge1 = Hoge(name: "Taro")
hoge1.volume=100
print(hoge1.volume)//100
var hoge0 = substituted a reference for hoge1//hoge1 for hoge0.
hoge0.volume=200
print(hoge1.volume)//200
// Both variables hoge0 and hoge1 have references to the same instance.
This is a reference-type technique in which operations (changes) to the variable hoge0
are reflected in the variable hoge1
, but this alone might make you wonder, "Why?"However, considering that the reference type of this class can provide a mechanism that reflects user input on the ViewControllerA
screen objects (for example, tables, collections, and so on).
At the same time, however, this mechanism means that if you substitute a reference for another class of instances for a variable that substitutes a reference for an instance of one class, you will no longer refer to an instance of the previous class.
class Hoge {
var name —String
var volume —Float=0
init(name:String){
self.name = name
}
}
var hoge1 = Hoge(name: "Taro")
hoge1.volume=100
print(hoge1.volume)//100
var hoge2 = Hoge(name: "Hanako")
hoge2.volume=50
print(hoge2.volume)//50
The hoge1 = hoge2 // variable hoge1 is substituted by a reference to an instance of name = "Hanako" that is substituted by hoge2
print(hoge1.name)//Hanako
print(hoge1.volume)//50
I believe that the above attempts (or experiments) have shown that the code you provided does not work at all as intended.
Below, away from the class reference type, I would like to write practical programming advice as a free gift.
First, write the initialization process for the UIViewController
subclass in the viewDidLoad()
method.Also, in property definitions, don't feel like you've done initialization by writing the default values.
Next, take a look at each reference that you can view to help with Xcode and make sure you have a better choice than the methods you're about to use.
Please refer to the code below.
import UIKit
import AVFoundation
classViewController:UIViewController, AVAudioPlayerDelegate{
@IBOutlet weak varplayButton:UIButton!
@IBOutlet weak var volumeSlider:UISlider!
varcymbalPlayer —AVAudioPlayer?
override func viewDidLoad(){
super.viewDidLoad()
iflet url=Bundle.main.url(forResource: "cymbal", withExtension: "mp3"){// If the resource is not complex with tiering, resource files can be directly designated.
cymbalPlayer=try?AVAudioPlayer(contentsOf:url)//Use simple exception handling patterns.
cymbalPlayer ?.delegate=self
iflet value = cymbalPlayer ?.volume {
volumeSlider.value = value
}
}
}
@ IBAction funcplayCymbal(_sender:UIButton){
cymbalPlayer?.play()//If the initialization process is done properly, you can play it in just one line.
sender.isEnabled=false//Do not press the button during playback.
}
// When the cymbalPlayerdelegate playback is finished, return the button to press.
funcaudioPlayerDidFinishPlaying(_player:AVAudioPlayer, successfully flag:Bool){
playButton.isEnabled=true
}
// volume control
@ IBAction func volumeLebel(_sender:UISlider){
cymbalPlayer?.volume=sender.value
}
}
The AVAudioPlayer
sound source has an initialization method with exception handling (throws
) because it is a bit unreliable, for example, data downloaded on the network or files that can be referenced by music apps.
The try?
syntax replaces exception handling with Optional Chaining and Optional Binding.
916 When building Fast API+Uvicorn environment with PyInstaller, console=False results in an error
574 Who developed the "avformat-59.dll" that comes with FFmpeg?
573 rails db:create error: Could not find mysql2-0.5.4 in any of the sources
613 GDB gets version error when attempting to debug with the Presense SDK (IDE)
© 2024 OneMinuteCode. All rights reserved.