하루에 0.01%라도 성장하자

Develop/iOS

iOS 음악 재생 앱 만들기 Part#1 - 앱 개발

뚠님 2019. 5. 14. 15:42
728x90
반응형

iOS

edwith에서 수강하던 강좌를 마쳤다. ( Swift 기초문법 )

우선은 Swift문법은 100% 다 익히고 응용할 수 있는 단계는 아니지만, 그래도 예제 코드나 이후 진행되는 프로그래밍 관련해서 보고 알아 볼 수 있는 정도의 수준은 되었다.

 

이번 강좌도 edwith에서 수강한다.

 

iOS프로그래밍 이라는 강좌이며 오리엔테이션과 총 5개의 프로젝트를 진행 하는 것 같다.

 

아무래도 어플을 만드는거다 보니, 기존 기초문법 강좌보다 디테일하게 설명하는 부분은 많지 않다. 

( 사용메소드 하나하나 사용법과 그 정의를 확인해가면서 하면 강좌가 진행될 수 없을 것이다 ... )

 

스위프트는 아니더라도 나름 개발 경력을 가지고 있기 때문에 흐름(?)상 어떤 느낌인지 알겠더라.

( 경력에 감사! )

 

그래도 내 블로그를 봐주는 사람들과, 그리고 미래의 내가 코드를 보고 못알아 볼 수 있기 때문에 강좌에서 설명하지 않은 부분도 짧게나마 주석으로 간단한 설명을 할 예정이다.

 


 

Xcode 사용

 

현재 나는 window로만 개발을 했기 때문에 Mac OS자체가 생소하고, 거기에 Xcode는 당연히 처음 쓴다.

그래서 블로그에 XCode사용법부터 작성해야 할까? 생각도 많이 했지만 구글을 통해 검색을 좀 해보니 굳이 내가 하지 않아도 되겠더라.

너무 많은 블로거들이 너무나도 정성스럽게 Xcode사용법을 작성했고, 나는 그정도의 퀄리티가 있는 포스팅을 할 자신이 없어졌다 .. ㅋㅋㅋ ( 귀찮아서 아님. )

 

따라서 별도의 Xcode사용법으로 포스팅을 진행 하지는 않고, 향후에 예제를 진행 하다가 ' 오 이거 꿀팁! ' 이라고 생각 되는 부분이 있다면 그때그때 포스팅을 할 생각이다.

 


 

음악 재생 앱

 

하나의 페이지에 음악재생을 제어하는 앱이다.

주어진 요구사항은 아래와 같다.

 

[ 요구사항 ]

  • 하나의 페이지로 구성한다
  • 재생 이미지와 정지이미지를 이용하여 현재 오디오가 재생 중인지 정지 중인지 확인 할 수 있어야 한다
  • 이미지 버튼을 클릭하면 재생, 정지 기능이 동작 해야 한다
  • 재생중인 음악의 시간을 사용자가 텍스트를 이용해 확인이 가능해야 한다
  • 슬라이더를 이용하여 원하는 재생 시간대로 이동할 수 있어야 한다
  • 재생이 종료되면 아이콘이 재생 아이콘으로 변경되어야 한다.

 

소스코드

 

import UIKit
import AVFoundation

class ViewController: UIViewController, AVAudioPlayerDelegate {

    var player : AVAudioPlayer!
    var timer : Timer!
    
    @IBOutlet weak var playBtn: UIButton!
    @IBOutlet weak var playTimeLabel: UILabel!
    @IBOutlet weak var playSilder: UISlider!

    // 재생 버튼을 클릭하면
    @IBAction func touchUpPlayPauseBtn( sender : UIButton){
        print("btn change");
        sender.isSelected = !sender.isSelected
        
        // sender가 선택되면 플레이어가 재생중인지 확인하고 처리
        if sender.isSelected {
            self.player?.play()
        } else {
            self.player?.pause()
        }
        
        // sender가 선택되면 타이머 처리를 할 것인지 확인
        if sender.isSelected{
            self.mamkeAndFireTimer()
        } else{
            self.invalidateTimer()
        }
    }
    
    // 플레이어 초기화.
    func initializePlayer(){
        guard let soundAsset : NSDataAsset = NSDataAsset(name : "sound") else {
            print("음원없음");
            return;
        }
        do {
            try self.player = AVAudioPlayer(data : soundAsset.data);
            self.player.delegate = self;
        } catch let error as NSError {
            print("초기화 실패");
            print("코드 : \(error.code), 메세지 : \(error.localizedDescription) ");
        }
        self.playSilder.maximumValue = Float(self.player.duration);
        self.playSilder.minimumValue = 0;
        self.playSilder.value = Float(self.player.currentTime);
    }
    
    // 레이블 업데이트.
    func updateTimeLabelText(time:TimeInterval){
        let minute : Int = Int(time/60);
        let second : Int = Int(time.truncatingRemainder(dividingBy: 60));
        let milisecond : Int = Int(time.truncatingRemainder(dividingBy: 1)*100);
        
        let timeText : String = String(format : "%02ld:%02ld:%02ld", minute, second, milisecond);
        self.playTimeLabel.text = timeText;
    }
    
    // 타이머를 만들고 수행해줄 메소드
    func mamkeAndFireTimer(){
        self.timer = Timer.scheduledTimer(withTimeInterval : 0.01, repeats: true, block : { [unowned self] (timer : Timer) in
            if self.playSilder.isTracking { return };
            self.updateTimeLabelText(time:self.player.currentTime);
            self.playSilder.value = Float(self.player.currentTime);
        })
        self.timer.fire();
    }
    
    
    // 플레이어 재생 관련 에러처리.
    func audioPlayerDecodeErrorDidOccur(_ player: AVAudioPlayer, error: Error?) {
        guard let error: Error = error else{
            print("플레이어 오류 발생");
            return
        }
        
        let message : String
        message = "플레이어 오류 발생 \(error.localizedDescription)";
        
        let alert : UIAlertController = UIAlertController(title:"알림", message : message, preferredStyle :UIAlertController.Style.alert);
        
        let okAction : UIAlertAction = UIAlertAction(title : "확인", style : UIAlertAction.Style.default) { ( action:UIAlertAction) -> Void in
            self.dismiss(animated: true, completion:nil)
        }
        
        alert.addAction(okAction)
        self.present(alert, animated:true, completion:nil)
    }
    
    // 음악 재생이 끝나면
    func audioPlayerDidFinishPlaying(_ player: AVAudioPlayer, successfully flag: Bool) {
        self.playBtn.isSelected = false;
        self.playSilder.value = 0;
        self.updateTimeLabelText(time: 0)
        self.invalidateTimer()
    }
    
    // 타이머 해제
    func invalidateTimer(){
        self.timer.invalidate();
        self.timer = nil;
    }
    
    override func viewDidLoad() {
        super.viewDidLoad()
        self.initializePlayer();
        // Do any additional setup after loading the view, typically from a nib.
    }

    // 슬라이더를 이용한 오디오 제어
    @IBAction func sliderValueControl(_ sender: UISlider) {
        self.updateTimeLabelText(time: TimeInterval(sender.value))
        if sender.isTracking{return}
        self.player.currentTime = TimeInterval(sender.value);
    }
    
}

 

코드내용은 위와 같다. 

( 이거 또한 iOS프로그래밍 동영상 강좌에서 나오는 소스코드를 직접 타이핑하여 작성한 것이다. )

 

보면 크게 어려운 내용은 없다. 문법공부를 미리 해서 코드상에서 딱히 해석이 되지 않는 것은 없는데, 

공부하면서 배우지 않은 메소드들이 조금 생소할 뿐이다.

예를 들면 UIAlertController가 있는데 ,

 

완성된 앱의 형태

 

음악 재생 앱

 

let alert : UIAlertController = UIAlertController(title:"알림", message : message, preferredStyle :UIAlertController.Style.alert);
        
let okAction : UIAlertAction = UIAlertAction(title : "확인", style : UIAlertAction.Style.default) { ( action:UIAlertAction) -> Void in
    self.dismiss(animated: true, completion:nil)

 

강의 내용과 현재 사용하고자 할 때 조금 문법이 달라 찾아보았다.

 

//강좌에서는
preferredStyle : UIAlertControllerStyle.alert
style : UIAlertActionStyle.default


//실제 사용하려면..
preferredStyle :UIAlertController.Style.alert
style : UIAlertAction.Style.default

 

이부분 외에는 크게 다른 내용이 없기 때문에 앱을 개발하는데 큰 문제는 없었다.

 


 

예제를 작성하면서 '오!?' 했었던 것은 버튼의 이미지를 지정해 줄 때 기본 이미지와 셀렉트 되었을때 이미지를 따로 지정할 수 있었던 것이 조금 놀라웠고 ( 안드로이드에서도 가능한가??? 사용해 본적이 없었던 것으로 ... ;; )

생각보다 UI를 만들고 Action을 설정하는데 편리하다고 느낄법 했다. 

 

표현이 조금 이상한데, 안드로이드 개발자 기준으로는 xml코딩으로 레이아웃을 잡는게 아직은 조금 더 편하다. iOS의 경우 드래그앤드롭으로 UI와 연결되는 변수를 만들어 줄 수 있고,  심지어 연결되는 메소드(이벤트 리스너 같은.. )를 만들 수 있다.

 

728x90
반응형