Bygg en MP3-spiller med AV-stiftelse

Hva du skal skape

AV Foundation er et rammeverk for å jobbe med lyd og visuelt media på iOS og OSX. Ved hjelp av AV Foundation kan du spille, fange opp og kode medie. Det er ganske omfattende rammeverk og for formålet med denne opplæringen vil vi fokusere på lyddelen. Spesielt vil vi bruke AVAudioPlayer klassen for å spille MP3-filer.

Startprosjekt

Jeg har gitt et startprosjekt som har alle handlingene og uttakene allerede konfigurert, og med de riktige metodene stubbet ut. Klassene prosjektet bruker, er allerede stubbet ut så vel, så vi kan dykke rett inn i koden. Du kan laste ned startprosjektet fra GitHub.

1. Koble til AV Foundation Framework

Før du kan bruke AV Foundation, må du koble prosjektet mot rammen. I Prosjektnavigator, sørg for at prosjektet er valgt. Under Generell kategorien, gå til Sammenhengende rammer og biblioteker og derfra velger du AVFoundation.framework.

2. Filereader Klasse

I startprosjektet finner du en fil som heter FileReader.swift. Åpne denne filen for å se innholdet.

importere UIKit klasse FileReader: NSObject 

Dette er en enkel stub av klassen som vi vil bruke til å lese filer fra disken. Det arver fra NSObject. Vi vil implementere en metode, readFiles, som vil være en type metode. Typemetoder lar deg ringe en metode på selve klassen, typen, i motsetning til en forekomst av klassen. Nedenfor er implementeringen av readFiles metode.

class func readFiles () -> [String] return NSBundle.mainBundle (). pathsForResourcesOfType ("mp3", inDirectory: null) som! [String]

Hovedpakken inneholder koden og ressursene for prosjektet ditt, og det er her at vi finner MP3-ene. Vi bruker metoden pathsForResourcesOfType (_: inDirectory :) metode, som returnerer en matrise som inneholder banenavnene for den angitte ressurstypen. I dette tilfellet søker vi etter type "Mp3". Fordi vi ikke er interessert i en bestemt katalog, passerer vi inn nil.

Denne klassen vil bli brukt av Mp3 spiller klassen, som vi vil jobbe med på neste.

3. Mp3 spiller Klasse

Deretter åpne MP3Player.swift og se innholdet.

importere UIKit import AVFoundation klasse MP3Player: NSObject, AVAudioPlayerDelegate 

Legg merke til at vi vedtar AVAudioPlayerDelegate protokoll. Denne protokollen erklærer en rekke nyttige metoder, hvorav en er audioPlayerDidFinishPlaying (_: hell :). Ved å implementere audioPlayerDidFinishPlaying (_: hell :) Metode, vi vil bli varslet når lyden er ferdig med å spille.

Trinn 1: Egenskaper

Legg til følgende til MP3Player.swift.

klasse MP3Player: NSObject, AVAudioPlayerDelegate var spiller: AVAudioPlayer? var currentTrackIndex = 0 var spor: [String] = [String] ()

De spiller eiendom vil være en forekomst av AVAudioPlayer klassen, som vi vil bruke til å spille, pause og stoppe MP3-ene. De currentTrackIndex variabel holder oversikt over hvilken MP3 som spilles. Endelig, den spor variabel vil være en rekke stier til listen over MP3 som er inkludert i programmets bunt.

Steg 2: i det

overstyr init () tracks = FileReader.readFiles () super.init () queueTrack (); 

Under initialisering påberoper vi oss Filereader's readFiles metode for å hente stiene til MP3 og lagre denne listen i spor array. Fordi dette er en utpekt initialiserer, må vi ringe i det metode for superklassen. Til slutt, vi ringer queueTrack, som vi skal skrive neste.

Trinn 3: queueTrack

Legg til følgende implementering for queueTrack metode til Mp3 spiller klasse.

func queueTrack () if (player! = nil) player = nil var feil: NSError? la url = NSURL.fileURLWithPath (spor [currentTrackIndex] som String) player = AVAudioPlayer (contentOfURL: url, feil: & feil) hvis la hasError = feil // SHOW ALERT ELLER ENKELT annet spiller? .delegate = selvspiller ?. prepareToPlay ()

Fordi vi vil instantiere en ny AVAudioPlayer forekom hver gang denne metoden heter, gjør vi litt housekeeping ved å sette inn spiller til nil.

Vi erklærer en valgfri NSError og en konstant url. Vi påberoper fileURLWithPath (_ :) for å hente banen til gjeldende MP3 og lagre verdien i url. Vi passerer spor array som parameter ved hjelp av currentTrackIndex som abonnementet. Husk at sporene inneholder stiene til MP3, ikke en referanse til MP3-filene selv.

For å instantiere spiller, vi passerer url konstant og feil variabel inn i AVAudioPlayers initialiserer. Hvis initialiseringen skjer, mislykkes den feil variabel er fylt med en beskrivelse av feilen.

Hvis vi ikke støter på en feil, setter vi spillerens delegat til selv- og påkalle prepareToPlay metode på spilleren. De prepareToPlay Metoden forlaster bufferne og kjøper lydmaskinvaren, noe som minimerer enhver lagring når du ringer til spille metode.

Trinn 4: spille

De spille Metoden kontrollerer først for å se om lyden allerede spiller ved å sjekke det passende navnet spiller eiendom. Hvis lyden ikke spiller, påkaller den spille metode av spiller eiendom.

 func play () hvis spiller? .playing == false player? .play ()

Trinn 5: Stoppe

De Stoppe Metoden kontrollerer først om lydspilleren allerede spiller. Hvis det er, påkaller det Stoppe metode og setter nåværende tid eiendom til 0. Når du påkaller Stoppe metode, det stopper bare lyden. Det tilbakestiller ikke lyden til begynnelsen, og derfor må vi gjøre det manuelt.

func stop () hvis spiller? .playing == sann spiller? .stop () spiller? .currentTime = 0

Trinn 6: pause

Akkurat som Stoppe metode, vi sjekker først for å se om lydspilleren spiller. Hvis det er, påberoper vi oss pause metode.

 func pause () hvis spilleren? .playing == true player? .pause ()

Trinn 7: nextSong

De nextSong (_: Boolsk) Metoden køer opp neste sang, og hvis spilleren spiller, spiller den sangen. Vi vil ikke ha den neste sangen som spilles hvis spilleren er pauset. Denne metoden kalles imidlertid også når en sang er ferdig med å spille. I så fall ønsker vi å spille den neste sangen, som er parameteren songFinishedPlaying er for.

func nextSong (songFinishedPlaying: Bool) var playerWasPlaying = false hvis spiller? .playing == true player? .stop () playerWasPlaying = true currentTrackIndex ++ hvis currentTrackIndex> = tracks.count currentTrackIndex = 0 køTrack () hvis playerWasPlaying | | songFinishedPlaying spiller? .play ()

De playerWasPlaying variabel brukes til å fortelle om spilleren spilte når denne metoden ble påkalt. Hvis sangen lekte, ringer vi på Stoppe metode på spiller og sett playerWasPlaying til ekte.

Deretter øker vi currentTrackIndex og sjekk for å se om den er større enn eller lik tracks.count. De telle Egenskapen til en matrise gir oss det totale antall elementer i matrisen. Vi må være sikre på at vi ikke prøver å få tilgang til et element som ikke finnes i spor array. For å forhindre dette, setter vi inn currentTrackIndex tilbake til det første elementet i gruppen hvis dette er tilfelle.

Til slutt påberoper vi oss queueTrack for å få den neste sangen klar og spille den sangen hvis heller playerWasPlaying eller songFinishedPlaying er ekte.

Trinn 8: previousSong

De previousSong Metoden fungerer veldig lik nextSong. Den eneste forskjellen er at vi reduserer currentTrackIndex og sjekk om det er lik 0. Hvis det er, setter vi det til indeksen for det siste elementet i matrisen.

func previousSong () var playerWasPlaying = false hvis spiller? .playing == true player? .stop () playerWasPlaying = true currentTrackIndex - hvis currentTrackIndex < 0  currentTrackIndex = tracks.count - 1  queueTrack() if playerWasPlaying  player?.play()   

Ved å benytte begge nextSong og previousSong metoder, vi er i stand til å sykle gjennom alle MP3-ene og starte over når vi kommer til begynnelsen eller slutten av listen.

Trinn 9: getCurrentTrackName

De getCurrentTrackName Metoden får navnet på MP3 uten utvidelsen.

func getCurrentTrackName () -> String la trackName = spor [currentTrackIndex] .lastPathComponent.stringByDeletingPathExtension return trackName

Vi får en referanse til hva den nåværende MP3 er ved å bruke spor [currentTrackIndex]. Husk imidlertid at disse er stiene til MP3-ene og ikke selve filene selv. Banene er ganske lange, fordi det er den fulle veien til MP3-filene.

På min maskin, for eksempel, det første elementet i spor array er lik "/Users/jamestyner/Library/Developer/CoreSimulator/Devices/80C8CD34-22AE-4F00-862E-FD41E2D8D6BA/data/Containers/Bundle/Application/3BCF8543-BA1B-4997-9777-7EC56B1C4348/MP3Player.app/Lonesome Road Blues.mp3". Denne banen ville være annerledes på en faktisk enhet selvfølgelig.

Vi har en stor streng som inneholder banen til MP3, men vi vil bare ha navnet på selve MP3-en. De NSString Klassen definerer to egenskaper som kan hjelpe oss. Som navnet tilsier, er det lastPathComponent Egenskapen returnerer den siste komponenten av en bane. Som du kanskje har gjettet, stringByDeletingPathExtension Egenskapen fjerner forlengelsen.

Trinn 10: getCurrentTimeAsString

De getCurrentTimeAsString Metoden bruker nåværende tid eiendom av spiller forekomst og returnerer den som en menneskelig lesbar streng (f.eks., 01:02).

 func getCurrentTimeAsString () -> String var sekunder = 0 var minutter = 0 hvis la tid = spiller? .currentTime sekunder = Int (tid)% 60 minutter = (Int (tid) / 60)% 60 Return String : "% 0.2d:% 0.2d", minutter, sekunder)

De nåværende tid Eiendommen er av typen NSTimeInterval, som bare er en typealias for en Dobbelt. Vi bruker litt matte for å få sekunder og minutter, sørger for at vi konverterer tid til en int siden vi trenger å jobbe med hele tall. Hvis du ikke er kjent med resten av operatøren (%), finner den resten etter oppdeling av ett nummer av en annen. Hvis tid variabel var lik 65, deretter sekunder ville være lik 5 fordi vi bruker 60.

Trinn 11: getProgress

De getProgress Metoden brukes av UIProgressView eksempel for å gi en indikasjon på hvor mye MP3 har spilt. Denne fremgangen er representert med en verdi fra 0.0 til 1.0 som en Flyte.

 funksjon

For å få denne verdien deler vi spiller's nåværende tid eiendom ved spiller's varighet eiendom, lagrer vi disse verdiene i variablene theCurrentTime og theCurrentDuration. Som nåværende tid, de varighet Eiendommen er av typen NSTimeInterval og det representerer varigheten av sangen i sekunder.

Trinn 12: setVolume

De setVolume (_: Float) metode påberoper seg setVolume metode av spiller forekomst.

func setVolume (volum: Float) spiller? .volume = volum 

Trinn 13: audioPlayerDidFinishPlaying (_: hell :)

De audioPlayerDidFinishPlaying (_: hell :) Metode er en metode for AVAudioPlayerDelegate protokoll. Denne metoden tar som parametere AVAudioPlayer eksempel og en boolsk. Den boolske er satt til ekte hvis lydspilleren er ferdig med å spille den nåværende sangen.

func audioPlayerDidFinishPlaying (spiller: AVAudioPlayer, vellykket flagg: Bool) hvis flagg == true nextSong (true)

Hvis sangen er ferdig med å spille, kaller vi nextSong metode, passerer inn ekte siden sangen avsluttet å spille alene.

Dette fullfører Mp3 spiller klasse. Vi vil revidere det litt senere, etter å ha gjennomført handlingene til ViewController klasse.

4. ViewController Klasse

Åpen ViewController.swift og se innholdet.

mport UIKit import AVFoundation klasse ViewController: UIViewController var mp3Player: MP3Player? var timer: NSTimer? @IBOutlet svak var spornavn: UILabel! @IBOutlet svak var trackTime: UILabel! @IBOutlet svak var fremgangBar: UIProgressView! overstyr func viewDidLoad () super.viewDidLoad () @IBAction func playSong (sender: AnyObject)  @IBAction func stopSong (sender: AnyObject)  @IBAction func pauseSong (sender: AnyObject)  @IBAction func playNextSong avsender: AnyObject)  @IBAction func setVolume (sender: UISlider)  @IBAction func playPreviousSong (sender: AnyObject)  overstyr func didReceiveMemoryWarning () super.didReceiveMemoryWarning () // Kast bort eventuelle ressurser som kan gjenopprettes. 

De mp3 spiller variabel er en forekomst av Mp3 spiller klasse vi implementerte tidligere. De tidsur variabel vil bli brukt til å oppdatere Tracktime og ProgressBar visninger hvert sekund.

I de neste trinnene vil vi gjennomføre handlingene til ViewController klasse. Men først bør vi instansere Mp3 spiller forekomst. Oppdater implementeringen av viewDidLoad metode som vist nedenfor.

overstyr func viewDidLoad () super.viewDidLoad () mp3Player = MP3Player () 

Trinn 1: playSong (_: AnyObject)

Skriv inn følgende i playSong (_: AnyObject) metode.

@IBAction func playSong (sender: AnyObject) mp3Player? .Play ()

I denne metoden bruker vi spille metode på mp3 spiller gjenstand. Vi er på et punkt der vi kan begynne å teste appen nå. Kjør appen og trykk på avspillingsknappen. Sangen skal begynne å spille.

Steg 2: stopSong (_: AnyObject)

De stopSong (_: AnyObject) Metode påberoper stoppmetoden på mp3 spiller gjenstand.

 @IBAction func stopSong (avsender: AnyObject) mp3Player? .Stop ()

Kjør appen igjen og trykk på avspillingsknappen. Du bør nå kunne stoppe sangen ved å trykke på stoppknappen.

Trinn 3: pauseSong (_: AnyObject)

Som du kanskje har gjettet, pauseSong (_: AnyObject) metode påberoper seg pause metode på mp3 spiller gjenstand.

@IBAction func pauseSong (sender: AnyObject) mp3Player? .Pause ()

Trinn 4: playNextSong (_: AnyObject)

IBAction func playNextSong (sender: AnyObject) mp3Player? .NextSong (false)

I playNextSong (_: AnyObject), vi påberoper nextSong metode på mp3 spiller gjenstand. Legg merke til at vi passerer falsk som en parameter, fordi sangen ikke fullførte å spille alene. Vi starter manuelt den neste sangen ved å trykke på neste knapp.

Trinn 5: forrigeSong (_: AnyObject)

 @IBAction func playPreviousSong (avsender: AnyObject) mp3Player? .RevligSong ()

Som du kan se, implementeringen av forrigeSong (_: AnyObject) Metoden ligner veldig på nextSong (_: AnyObject). Alle knappene på MP3-spilleren skal fungere nå. Hvis du ikke har testet appen ennå, ville det være en god tid å sørge for at alt fungerer som forventet.

Trinn 6: setVolume (_: UISlider)

De setVolume (_: UISlider) metode påberoper seg setVolume metode på mp3 spiller gjenstand. Volumegenskapen er av typen Flyte. Verdien varierer fra 0.0 til 1.0. De UISlider objektet er satt opp med 0.0 som minimumsverdi og 1.0 som sin maksimale verdi.

 @IBAction func setVolume (sender: UISlider) mp3Player? .SetVolume (sender.value)

Kjør appen en gang til og spill med volumreglaget for å teste at alt fungerer som det skal.

Trinn 7: startTimer

De startTimer metode instantiates en ny NSTimer forekomst.

 func startTimer () timer = NSTimer.scheduledTimerWithTimeInterval (1.0, mål: selvvalg: Selector ("updateViewsWithTimer:"), brukerInfo: null, gjentakelser: sant)

De scheduledTimerWithTimeInterval (_: mål: Velger: Userinfo: gjentagelser :) initialiserer tar som parametre antall sekunder mellom avfyring av timeren, objektet som det skal kalles en metode på angitt av velger, Metoden som blir kalt når timeren brenner, en valgfri brukerinformasjon ordboken, og om timeren gjentas eller ikke, før den blir ugyldiggjort.

Vi bruker en metode som heter updateViewsWithTimer (_: NSTimer) Som selector, så vil vi skape det neste.

Trinn 8: updateViewsWithTimer (_: NSTimer)

De updateViewsWithTimer (_: NSTimer) metode kalles updateViews metode som vi vil implementere i neste trinn.

func updateViewsWithTimer (theTimer: NSTimer) updateViews ()

Trinn 9: updateViews

De updateViews Metoden oppdaterer Tracktime og ProgressBar visninger.

func updateViews () trackTime.text = mp3Player? .getCurrentTimeAsString () hvis la fremgang = mp3Player? .getProgress () progressBar.progress = fremgang 

De tekst tilhører Tracktime er oppdatert med nåværende tid eiendom, formatert som en streng ved å påkalle getCurrentTimeAsString metode. Vi erklærer en konstant framgang bruker mp3 spiller's getProgress metode og sett progressBar.progress bruker den konstanten.

Trinn 10: Tilkobling av timeren

Nå må vi ringe startTimer metode på de riktige stedene. Vi må starte timeren i playSong (_: AnyObject) metode, den playNextSong (_: AnyObject) metode, og playPreviousSong (_: AnyObject) metode.

@IBAction func playSong (avsender: AnyObject) mp3Player? .Play () startTimer () 
 @IBAction func playNextSong (sender: AnyObject) mp3Player? .NextSong (false) startTimer () 
@IBAction func playPreviousSong (avsender: AnyObject) mp3Player? .PreviousSong () startTimer () 

Trinn 11: Stoppe timeren

Vi må også stoppe tidsur når du trykker på pause og stoppknappene. Du kan stoppe tidsur objekt ved å påkalle ugyldig metode på NSTimer forekomst.

@IBAction func stopSong (sender: AnyObject) mp3Player? .Stop () updateViews () timer? .Validere () 
@IBAction func pauseSong (sender: AnyObject) mp3Player? .Pause () timer? .Validere ()

Trinn 12: setTrackName

De setTrackName Metoden setter tekst tilhører trackName ved å påkalle getCurrentTrackNamemp3 spiller gjenstand.

func setTrackName () trackName.text = mp3Player? .getCurrentTrackName ()

Trinn 13: setupNotificationCenter

Når en sang avsluttes, skal den automatisk vise den neste sangens navn og begynne å spille den sangen. Også, når brukeren trykker på spill, neste eller tidligere knapper, setTrackName Metoden bør påberopes. Det ideelle stedet å gjøre dette er queueTrack metode av Mp3 spiller klasse.

Vi trenger en måte å ha på Mp3 spiller klassen forteller ViewController klasse for å påkalle setTrackName metode. For å gjøre det, bruker vi NSNotificationCenter klasse. Meldingssentralen gir en måte å kringkaste informasjon gjennom et program. Ved å registrere som observatør med varslingssenteret, kan en gjenstand motta disse sendingene og utføre en operasjon. En annen måte å utføre denne oppgaven på er å bruke delegasjonsmønsteret.

Legg til følgende metode for ViewController klasse.

 func setupNotificationCenter () NSNotificationCenter.defaultCenter (). addObserver (selv, selector: "setTrackName", navn: "SetTrackNameText", objekt: null) 

Vi får først en referanse til standardvarslingssenteret. Vi anvender deretter addObserver (_: selector: navn: objekt :) metode på varslingssenteret. Denne metoden godtar fire parametere:

  • objektet registrerer som observatør, selv- i dette tilfellet
  • meldingen som vil bli sendt til observatøren når meldingen er lagt ut
  • navnet på varselet for å registrere observatøren
  • objektet hvis meldinger observatøren ønsker å motta

Ved å passere inn nil Som det siste argumentet lytter vi etter hvert varsel som har et navn på SetTrackNameText.

Nå må vi ringe denne metoden i visningskontrolløren viewDidLoad metode.

overstyr func viewDidLoad () super.viewDidLoad () mp3Player = MP3Player () setupNotificationCenter () 

Trinn 14: Publisering av varslingen

For å legge inn varselet, påberoper vi oss postNotificationName (_: objekt :) metode på standardvarslingssenteret. Som jeg nevnte tidligere, vil vi gjøre dette i queueTrack metode av Mp3 spiller klasse. Åpen MP3Player.swift og oppdatere queueTrack metode som vist nedenfor.

 func queueTrack () if (player! = nil) player = nil var feil: NSError? la url = NSURL.fileURLWithPath (spor [currentTrackIndex] som String) player = AVAudioPlayer (contentOfURL: url, feil: & feil) hvis la hasError = feil // SHOW ALERT ELLER ENKELT annet spiller? .delegate = selvspiller ?. prepareToPlay () NSNotificationCenter.defaultCenter (). postNotificationName ("SetTrackNameText", objekt: null)

Hvis du tester appen nå og lar en sang spilles helt gjennom, bør den begynne å spille neste sang automatisk. Men du lurer kanskje på hvorfor sangens navn ikke kommer opp under den første sangen. De i det metode av Mp3 spiller klassen ringer på queueTrack metode, men siden den ikke har fullført initialiseringen, har den ingen innvirkning.

Alt vi trenger å gjøre er å ringe manuelt setTrackName metode etter at vi har initialisert mp3 spiller gjenstand. Legg til følgende kode i viewDidLoad metode i ViewController.swift.

 overstyr func viewDidLoad () super.viewDidLoad () mp3Player = MP3Player () setupNotificationCenter () setTrackName () updateViews ()

Du vil merke at jeg også ringte updateViews metode. På denne måten viser spilleren en tid på 00:00 i begynnelsen. Hvis du tester appen nå, bør du ha en fullt fungerende MP3-spiller.

Konklusjon

Dette var en ganske lang opplæring, men du har nå en funksjonell MP3-spiller for å bygge og utvide på. Et forslag er å la brukeren velge en sang som skal spilles ved å implementere en UITableView under spilleren. Takk for at du leser, og jeg håper du har lært noe nyttig.