본문 바로가기
Dot/iOS

iOS) 간단한 타이머 만들기

by jum0 2020. 1. 5.

Udemy에서 인강을 듣고 있는데, 복습하지 않으면 다 잊어버릴 것만 같아서 새롭게 배운 것을 토대로 비슷하게 만들어보려고 합니다.

이번에 배운 것은 타이머 기능을 하는 애플리케이션인데, 애플리케이션이라고 하기도 뭐하지만 이런 것들이 다 피가 되고 살이 될 것이라 굳게 믿습니다!!

그럼 시작하겠습니다!

구성과 기능은 다음과 같습니다.

  • 10초, 20초, 30초의 타이머를 가진 버튼 세 개.
  • 각 버튼 누르면 위 쪽에 시작을 알려줌. 시간이 끝나도 알려줌.
  • 시간이 흘러가는 것은 progress View를 통해서 확인 가능.
  • 끝나면 소리가 나옴.

먼저 레이아웃을 잡아보면 다음과 같습니다.

여기서 주의할 점은 위의 사진처럼 Button의 Title에 글씨를 썼는데, 사진처럼 표시되지 않는 경우예요.

그 이유는 Twenty Secodns Button이 Twenty Seconds ImageView에 묻혀서 그래요!

View Controller에서 아래에 가까울수록 여러 object들이 겹쳤을 때 위에 표시됩니다! (포토샵과 반대로 생각하면 돼요!)

 

시작하기 앞서, 간단하게 확인해볼 부분이 있는데요.

Title Label의 attributes inspector에서 Lines를 0으로 하면 글자가 길어져 공간을 벗어나게 되어도 다 보이도록 할 수 있다는 것입니다.

뿐만 아니라, Autoshrink 부분을 통해서 글씨가 길어질 경우, 글자를 자동으로 줄어들도록 설정할 수 있어요.

 

그럼, 첫 번째 기능으로는 각 버튼을 눌렀을 때, Title View에 'Start'라는 단어가 표시되도록 하는 거예요.

먼저 title과 button들을 코드와 연결해줍니다.

title은 IBOutlet(Interface Builder Outlet)으로, button들은 IBAction으로 연결합니다. 여기서 IBAction 'buttonPressed'라는 함수에 버튼 세 개를 같이 묶어줍니다. 그리고 그 안에

textLabel.text = "Start"

코드를 넣어줍니다.

 

다음으로 버튼을 누르면 타이머가 작동되도록 하는 코드입니다.

버튼을 누르면 남은 Start라는 글씨가 나오고 남은 시간이 계속 업데이트되도록 했습니다.

apple developer documentation에서 검색해보니, scheduledTimer 메서드 안에 timeInterval은 시간의 간격으로 1.0이면 1초의 딜레이 후 호출(?)한다고 생각하면 될 것 같습니다. 그런데 속성으로 repeats을 true로 함으로써 1초마다 호출하게 된다고 생각하면 될 것 같아요.

target은 documentation을 보니 이렇게 나와있습니다.

 타이머가 작동될 때 selector에 의해 명시된 메시지를 보낼 개체라고. 타이머는 타깃이 무효화될 때까지 강한 참조를 유지한다고. 사실 아직 느낌이 안옵니다. 네. 일단 넘어갈게요ㅠ (완벽하게 이해하고 싶다ㅠ)

selector 또한 애플 문서님께서 말씀하시길, 타이머가 작동할 때 타깃에게 보내는 메시지라고 설명해주시고 있습니다.

여기서 보니, 타이머가 작동할 때 실행되는 메서드 정도인 것 같아요.

아래 실행되는 메서드 앞에 @objc가 붙어 있는데, 이건 스위프트에서 objective-c 런타임과 상호 작용해야 하는 경우 swift에게 알려주는 거라고 하네요. 제 생각으로는 low-level 쪽이랑 관계가 있는 것 같아서 일단은 넘어갈게요. (그냥 다 넘어가는 듯ㅠ)

아무튼 이 메서드에서는 0보다 크면 계속 Label에 남은 시간이 표시되도록 했고, 끝나면 End가 표시돼요.

 

그런데, 문제가 있었어요.

10초 버튼을 누르고, 20초 버튼을 누르면 시간이 0.5초에 1씩 깎이더라고요. 거기에 30초 버튼을 또 누르면 1초를 3개로 나눈 간격만큼 깎여서 시간이 이상하게 됩니다ㅠ

그래서 다음과 같이 추가했습니다.

Timer() 인스턴스를 생성해서 버튼을 누를 때마다 처음으로 timer.invalidate() 해서 작동하지 않도록 합니다. 또, else가 되어서도 Label에 표시되는 것은 "End"이지만 타이머가 계속 작동되고 있으므로 여기에도 추가합니다.

 

세 번째는 시간의 경과를 progress View를 통해서 보여주도록 해볼게요.

그림과 같이 레이아웃을 잡고 코드에 연결했어요. progressView에서 Height는 두께가 됩니다.

progressView의 속성 중에 progress는 0.0에서 1.0까지를 갖게 되는데, 이것은 쉽게 말해서 막대의 퍼센트를 나타냅니다. 막대의 100퍼센트는 1.0, 0퍼센트는 0.0을 의미합니다.

그래서 버튼을 누르는 순간은 progressView.progress를 0.0으로 초기화합니다.

 

이 부분의 다음에서 메커니즘이 조금 바뀌면서 변수 명도 바뀌었는데, 먼저 변수 totalTime과 presentTime을 선언했습니다. totalTime은 기존의 count의 이름을 변경한 것으로 전체 시간(여기서는 10초, 20초, 30초)을 의미하고, presentTime은 현재 시간으로 1초씩 증가할 때마다의 시간을 의미합니다.

 

마지막은 타이머의 시간이 다 되었을 때, 음악이 나오게 하는 기능입니다.

음악은 요즘 유투버들의 영상에서 많이 들을 수 있는 효과음 두둥탁이 갑자기 떠올라서 이걸로 정했습니다.

음악을 끌어서 왼쪽 메뉴에 넣어줍니다.

local에 있는 리소스는 Bundle.main.url을 통해서 접근할 수 있어요. forResource 옆에는 파일의 이름을, withExtension 옆에는 확장자명을 써주면 됩니다.

파일이 존재하지 않을 수도 있어서 실제로는 guard와 try catch 구문을 이용해서 감싼다고 하네요. 이 부분에 대해서는 좀 더 공부해봐야겠습니다!

 

혹시라도 틀린 부분 있으면 알려주세요! 감사합니다:)

반응형

댓글