[스위프트 기초] 6장 얼럿 사용해보기

    얼럿(Alert)?

    화면에 경고 메세지를 표시하는 앱. 경고 확인 뿐만 아니라 두 가지 이상의 선택을 요구할 수 있고 특정 작업도 수행할 수 있음

    import UIKit
    
    class ViewController: UIViewController {
        @IBOutlet var mainImg: UIImageView!
        
        let eatSnow = UIImage(named: "snow1.JPG")
        let spitSnow = UIImage(named: "snow2.JPG")
        let imgCate = UIImage(named: "cat1.JPG")
        
        var isEatSnow = true
        
        override func viewDidLoad() {
            super.viewDidLoad()
            // Do any additional setup after loading the view.
            
            mainImg.image = eatSnow
        }
        @IBAction func btnEat(_ sender: UIButton) {
            if (isEatSnow == true){
                let EatAlert = UIAlertController(title: "경고", message: "현재 먹는 상태입니다", preferredStyle: UIAlertController.Style.alert)
                // 컨트롤러 생성
                let onAction = UIAlertAction(title: "네, 알겠습니다", style: UIAlertAction.Style.default, handler: nil)
                EatAlert.addAction(onAction) //onAction을 eatAlert에 추가
                present(EatAlert, animated: true, completion: nil) //present 메서드 실행
            }
            else{
                mainImg.image = eatSnow
                isEatSnow=true
            }
        }
        @IBAction func btnSpit(_ sender: UIButton) {
        }
        @IBAction func btnCat(_ sender: UIButton) {
        }

        @IBAction func btnSpit(_ sender: UIButton) {
            if(isEatSnow){
                let spitAlert = UIAlertController(title: "사람 뱉기", message: "사람을 뱉겠습니까?", preferredStyle: UIAlertController.Style.alert)
                let spitAction = UIAlertAction(title: "네", style: UIAlertAction.Style.default, handler: {
                        ACTION in self.mainImg.image = self.spitSnow
                        self.isEatSnow=false
                })
                let cancelAction = UIAlertAction(title: "아니오", style: UIAlertAction.Style.default, handler: nil)
                
                spitAlert.addAction(spitAction)
                spitAlert.addAction(cancelAction)
                
                present(spitAlert, animated: true, completion: nil)
            }
        }

    alert 에 action 을 추가할때는 반드시 self 붙여야 함. 


    cf. 익명함수 

    func completWork (finished: Bool)
    -> () {
    	print ("complete : \(finished)")
    }
    
    //Bool 타입의 finished 매개변수를 받아 출력하는 함수, 리턴 x 
    
    //익명 함수 형태로 바꿀 경우
    {
    	(finished:Bool) -> in
    	print("complete : \(finished)")
    }
    
    // {(매개변수) -> (반환타입)in 실행구문}
    //혹은 반환타입을 미리 설정해둔 경우 생략도 가능
    
    {
    	(finished:Bool) in
        print("complete: \(finished)")
    }
    //(매개변수) in 실행구문

    Reference to property 'spitSnow' in closure requires explicit use of 'self' to make capture semantics explicit
    -> 해결방법 : self 등 정확한 지칭 붙여주기

    ...

    정상작동

    @IBAction func btnCat(_ sender: UIButton) {
            
            let removeSnow = UIAlertController(title: "눈 제거", message: "눈사람을 치울까요?", preferredStyle: UIAlertController.Style.alert)
            let offAction = UIAlertAction(title: "아니요, 뱉습니다.", style: UIAlertAction.Style.default, handler: {
                ACTION in self.mainImg.image = self.spitSnow
                self.isEatSnow=false
            })
            let onAction = UIAlertAction(title: "아니요, 먹습니다.", style: UIAlertAction.Style.default) {
                ACTION in self.mainImg.image = self.eatSnow
                self.isEatSnow = true
            }
            //핸들러 매개변수 없이 뒤에 넣어도 정상적으로 작동.
            let removeAction = UIAlertAction(title:"네, 고양이 보여주세요.", style: UIAlertAction.Style.destructive, handler: {
                ACTION in self.mainImg.image = self.imgCat
                self.isEatSnow = false
            })
            
            removeSnow.addAction(offAction)
            removeSnow.addAction(onAction)
            removeSnow.addAction(removeAction)
            
            present(removeSnow, animated: true, completion: nil)
            
        }

    action 에서 default 스타일과 destructive 스타일의 차이도 확인 가능


    도전! 알람시계 만들기

    현재 시간이 선택한 시간과 같아지면 얼럿으로 알람 메세지를 만드는 알람 시계를 만들어 보세요. 
    -조건
    [네, 알겠습니다]를 누른 후에는 1분동안 알람 창이 나타나지 않게 설정

    1차 시도 

    import UIKit
    
    class ViewController: UIViewController {
        
        @IBOutlet var lbTimeNow: UILabel!
        @IBOutlet var lbTimeSelect: UILabel!
        @IBOutlet var datePickerView: UIDatePicker!
        
        let timeSector: Selector = #selector(ViewController.updateTime)
        let interval = 1.0
        
        var alarmTime:String?
        var currentTime:String?
        
        override func viewDidLoad() {
            super.viewDidLoad()
            
            Timer.scheduledTimer(timeInterval: interval, target: self, selector: timeSector, userInfo: nil, repeats: true) //여기서 0.1마다 timeSectior라고 정의된 updateTime 함수를 호출하는 것!!!
        }
        
        @IBAction func pickedDateChanged(_ sender: UIDatePicker) {
            let datePickerView = sender //datePickerView 라는 상수에 UIDatePicker의 자료형 인수 (sender)가 저장됨.
            let formatter = DateFormatter()
            formatter.dateFormat = "hh:mm aaa"
            alarmTime = formatter.string(from: datePickerView.date)
            lbTimeSelect.text = alarmTime
            checkTime()
        }
        
        @objc func updateTime (){
            let date = NSDate() // 현재 시간을 NSDate 함수를 통해서 가져옴
            let formatter = DateFormatter()
            formatter.dateFormat = "hh:mm aaa"
            currentTime = formatter.string(from: date as Date)
            lbTimeNow.text=currentTime
            checkTime()
        }
        
        @objc func checkTime () {
            
            print("checkTime call : \(currentTime ?? "없"), \(alarmTime ?? "없")")
            
            if(alarmTime == currentTime){
                let timerAlert = UIAlertController(title: "알림", message: "설정된 시간입니다!", preferredStyle: UIAlertController.Style.alert)
                
                let alertAnswer = UIAlertAction(title: "네, 알겠습니다.", style: UIAlertAction.Style.default, handler:{
                    // 1분동안 울리지 않으려면? 방법 1. interval을 조절한다.
                    // 단점: 다시 조정해 줘야 함, let 에서 var 로 바꿔야 함.
                    //ACTION in self.interval = 60.0
                    //방법 2. 그냥 alarmTime을 변경 ( 어차피 선택시간은 datePicker 가 변경될 때 표시)
                    //
                    Action in self.alarmTime = ""
                })
                timerAlert.addAction(alertAnswer)
                present(timerAlert, animated: true, completion: nil)
            }
        }
    }

    제대로 기능은 하지만, 1초마다 확인할 필요는 없는 것 같다. 

    //기본 1초에 한 번 호출
        @objc func updateTime (){
            let date = NSDate() // 현재 시간을 NSDate 함수를 통해서 가져옴
            let formatter = DateFormatter()
            
            formatter.dateFormat = "yyyy-MM-dd HH:mm:ss EEE"
            lbTimeNow.text="현재시간: "+formatter.string(from: date as Date) //라벨 표시 (1초마다)
            
            
            formatter.dateFormat = "hh:mm aaa" //분으로 자르기
    
            if(currentTime != formatter.string(from: date as Date)){
                print("1분마다 체크하는지 확인")
                currentTime = formatter.string(from: date as Date)
                checkTime()
            }
            
        }

    update time을 수정했다. 

     

    그리고 나서 생각해보니 두 가지 의문이 생겼다. 

    1. checkTime 함수를 매번 호출해서 확인하는게 효율적인가?

    2. DateFormatter()를 매 함수마다 새로 변수로 만들어서 활용하는데, 전역 변수로 하나 만들어 두는게 효율적인거 아닌가? 

     

    1번은... interval 자체를 60초로 만들면 중간에? 지금 시간으로 변경하면 확인할 수가 없기 때문에 잘 모르겠고...

    2번은 이전에 date picker 활용할 때 했던대로 그냥 생각 없이 했던 것인데, 아무래도 전역변수로 만드는게 효율적인 것 같다. 마지막으로 수정. 

    import UIKit
    
    class ViewController: UIViewController {
        
        @IBOutlet var lbTimeNow: UILabel!
        @IBOutlet var lbTimeSelect: UILabel!
        @IBOutlet var datePickerView: UIDatePicker!
        
        let timeSector: Selector = #selector(ViewController.updateTime)
        let interval = 1.0
        
        var alarmTime:String?
        var currentTime:String?
        
        let formatter = DateFormatter()
        
        override func viewDidLoad() {
            super.viewDidLoad()
            
            Timer.scheduledTimer(timeInterval: interval, target: self, selector: timeSector, userInfo: nil, repeats: true) //여기서 0.1마다 timeSectior라고 정의된 updateTime 함수를 호출하는 것!!!
        }
        
        @IBAction func pickedDateChanged(_ sender: UIDatePicker) {
            let datePickerView = sender //datePickerView 라는 상수에 UIDatePicker의 자료형 인수 (sender)가 저장됨.
            formatter.dateFormat = "hh:mm aaa"
            alarmTime = formatter.string(from: datePickerView.date)
            
            formatter.dateFormat = "선택시간: "+"yyyy-MM-dd HH:mm EEE"
            lbTimeSelect.text = formatter.string(from: datePickerView.date)
            checkTime()
        }
        
        //기본 1초에 한 번 호출
        @objc func updateTime (){
            let date = NSDate() // 현재 시간을 NSDate 함수를 통해서 가져옴
            
            formatter.dateFormat = "yyyy-MM-dd HH:mm:ss EEE"
            lbTimeNow.text="현재시간: "+formatter.string(from: date as Date) //라벨 표시 (1초마다)
            
            formatter.dateFormat = "hh:mm aaa" //분으로 자르기
    
            if(currentTime != formatter.string(from: date as Date)){
                print("1분마다 체크하는지 확인")
                currentTime = formatter.string(from: date as Date)
                checkTime()
            }
            
        }
        
        @objc func checkTime () {
            
    //        print("checkTime call : \(currentTime ?? "없"), \(alarmTime ?? "없")")
            
            if(alarmTime == currentTime){
                let timerAlert = UIAlertController(title: "알림", message: "설정된 시간입니다!", preferredStyle: UIAlertController.Style.alert)
                
                let alertAnswer = UIAlertAction(title: "네, 알겠습니다.", style: UIAlertAction.Style.default, handler:{
                    // 1분동안 울리지 않으려면? 방법 1. interval을 조절한다.
                    // 단점: 다시 조정해 줘야 함, let 에서 var 로 바꿔야 함.
                    //ACTION in self.interval = 60.0
                    //방법 2. 그냥 alarmTime을 변경 ( 어차피 선택시간은 datePicker 가 변경될 때 표시)
                    //
                    Action in self.alarmTime = ""
                })
                timerAlert.addAction(alertAnswer)
                present(timerAlert, animated: true, completion: nil)
            }
        }
       
        
    }

     

    끝!

    댓글